home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / networking / misc / wu-ftpd-37.14.lha / wu-ftpd / src / ftpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-20  |  83.6 KB  |  3,237 lines

  1. /* Copyright (c) 1985, 1988, 1990 Regents of the University of California.
  2.  * All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions are
  6.  * met: 1. Redistributions of source code must retain the above copyright
  7.  * notice, this list of conditions and the following disclaimer. 2.
  8.  * Redistributions in binary form must reproduce the above copyright notice,
  9.  * this list of conditions and the following disclaimer in the documentation
  10.  * and/or other materials provided with the distribution. 3. All advertising
  11.  * materials mentioning features or use of this software must display the
  12.  * following acknowledgement: This product includes software developed by the
  13.  * University of California, Berkeley and its contributors. 4. Neither the
  14.  * name of the University nor the names of its contributors may be used to
  15.  * endorse or promote products derived from this software without specific
  16.  * prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
  19.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21.  * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
  22.  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  24.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28.  * SUCH DAMAGE. 
  29.  */
  30.  
  31. #ifndef lint
  32. char copyright[] =
  33. "@(#) Copyright (c) 1985, 1988, 1990 Regents of the University of California.\n\
  34.  All rights reserved.\n";
  35. #endif /* not lint */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)ftpd.c  5.40 (Berkeley) 7/2/91";
  39. #endif /* not lint */
  40.  
  41. /* FTP server. */
  42. #include "config.h"
  43.  
  44. #include <sys/types.h>
  45. #include <sys/param.h>
  46. #include <sys/stat.h>
  47. #include <sys/ioctl.h>
  48. #include <sys/socket.h>
  49. #include <sys/file.h>
  50. #include <sys/wait.h>
  51.  
  52. #ifdef AIX
  53. #include <sys/id.h>
  54. #include <sys/priv.h>
  55. #endif
  56.  
  57. #include <netinet/in.h>
  58. #include <netinet/in_systm.h>
  59. #include <netinet/ip.h>
  60.  
  61. #define FTP_NAMES
  62. #include <arpa/ftp.h>
  63. #include <arpa/inet.h>
  64. #include <arpa/telnet.h>
  65.  
  66. #include <ctype.h>
  67. #include <stdio.h>
  68. #include <signal.h>
  69. #include <pwd.h>
  70. #include <setjmp.h>
  71. #include <netdb.h>
  72. #include <errno.h>
  73. #include <string.h>
  74. #include <varargs.h>
  75. #ifdef SYSSYSLOG
  76. #include <sys/syslog.h>
  77. #else
  78. #include <syslog.h>
  79. #endif
  80. #include <time.h>
  81. #ifdef AMIGA
  82. #include <bsdsocket.h>
  83. #include <libraries/multiuser.h>
  84. #include <proto/multiuser.h>
  85. #include <proto/exec.h>
  86. #include <proto/dos.h>
  87. #include "AmiTCP:src/netlib/netlib.h" /* for set_errno */
  88. #endif
  89. #include "conversions.h"
  90. #include "extensions.h"
  91. #include "pathnames.h"
  92.  
  93. #ifdef M_UNIX
  94. #include <arpa/nameser.h>
  95. #include <resolv.h>
  96. #endif
  97.  
  98. #if defined(SVR4) || defined(ISC) || defined(AMIGA)
  99. #include <fcntl.h>
  100. #endif
  101.  
  102. #ifdef HAVE_SYSINFO
  103. #include <sys/systeminfo.h>
  104. #endif
  105.  
  106. #ifdef SHADOW_PASSWORD
  107. #include <shadow.h>
  108. #endif
  109.  
  110. #ifdef KERBEROS
  111. #include <sys/types.h>
  112. #include <auth.h>
  113. #include <krb.h>
  114. #endif
  115.  
  116. #ifdef ULTRIX_AUTH
  117. #include <auth.h>
  118. #include <sys/svcinfo.h>
  119. #endif
  120.  
  121. #ifdef HAVE_DIRENT
  122. #include <dirent.h>
  123. #else
  124. #include <sys/dir.h>
  125. #endif
  126.  
  127. #ifndef TRUE
  128. #define  TRUE   1
  129. #endif
  130.  
  131. #ifndef FALSE
  132. #define  FALSE  !TRUE
  133. #endif
  134.  
  135. /* File containing login names NOT to be used on this machine. Commonly used
  136.  * to disallow uucp. */
  137. extern int errno;
  138. extern int pidfd;
  139. extern char *ctime(const time_t *);
  140. #ifndef NO_CRYPT_PROTO
  141. extern char *crypt(const char *, const char *);
  142. #endif
  143. extern char version[];
  144. extern char *home;              /* pointer to home directory for glob */
  145. extern FILE *ftpd_popen(char *program, char *type, int closestderr),
  146.  *fopen(const char *, const char *),
  147.  *freopen(const char *, const char *, FILE *);
  148. extern int ftpd_pclose(FILE *iop),
  149.   fclose(FILE *);
  150. extern char *getline(),
  151.  *realpath(char *pathname, char *result);
  152. extern char cbuf[];
  153. extern off_t restart_point;
  154.  
  155. struct sockaddr_in ctrl_addr;
  156. struct sockaddr_in data_source;
  157. struct sockaddr_in data_dest;
  158. struct sockaddr_in his_addr;
  159. struct sockaddr_in pasv_addr;
  160.  
  161. int data;
  162. jmp_buf errcatch,
  163.   urgcatch;
  164. int logged_in;
  165. struct passwd *pw;
  166. int debug;
  167. int timeout = 900;              /* timeout after 15 minutes of inactivity */
  168. int maxtimeout = 7200;          /* don't allow idle time to be set beyond 2
  169.                                  * hours */
  170. int logging;
  171. int log_commands = 1;
  172. int anonymous;
  173. int guest;
  174. int type;
  175. int form;
  176. int stru;                       /* avoid C keyword */
  177. int mode;
  178. int usedefault = 1;             /* for data transfers */
  179. int pdata = -1;                 /* for passive mode */
  180. int transflag;
  181. off_t file_size;
  182. off_t byte_count;
  183.  
  184. #if !defined(CMASK) || CMASK == 0
  185. #undef CMASK
  186. #define CMASK 002
  187. #endif
  188. mode_t defumask = CMASK;           /* default umask value */
  189. char tmpline[7];
  190. char hostname[MAXHOSTNAMELEN];
  191. char remotehost[MAXHOSTNAMELEN];
  192. char remoteaddr[MAXHOSTNAMELEN];
  193.  
  194. /* log failures     27-apr-93 ehk/bm */
  195. #ifdef LOG_FAILED
  196. #define MAXUSERNAMELEN    32
  197. char the_user[MAXUSERNAMELEN];
  198. #endif
  199.  
  200. /* Access control and logging passwords */
  201. int use_accessfile = 1;
  202. char guestpw[MAXHOSTNAMELEN];
  203. char privatepw[MAXHOSTNAMELEN];
  204. int nameserved = 0;
  205. extern char authuser[];
  206. extern int authenticated;
  207.  
  208. /* File transfer logging */
  209. int xferlog = 0;
  210. int log_outbound_xfers = 0;
  211. int log_incoming_xfers = 0;
  212.  
  213. /* Allow use of lreply(); this is here since some older FTP clients don't
  214.  * support continuation messages.  In violation of the RFCs... */
  215. int dolreplies = 1;
  216.  
  217. /* Spontaneous reply text.  To be sent along with next reply to user */
  218. char *autospout = NULL;
  219. int autospout_free = 0;
  220.  
  221. /* allowed on-the-fly file manipulations (compress, tar) */
  222. int mangleopts = 0;
  223.  
  224. /* number of login failures before attempts are logged and FTP *EXITS* */
  225. int lgi_failure_threshold = 5;
  226.  
  227. /* Timeout intervals for retrying connections to hosts that don't accept PORT
  228.  * cmds.  This is a kludge, but given the problems with TCP... */
  229. #define SWAITMAX    90          /* wait at most 90 seconds */
  230. #define SWAITINT    5           /* interval between retries */
  231.  
  232. int swaitmax = SWAITMAX;
  233. int swaitint = SWAITINT;
  234.  
  235. SIGNAL_TYPE lostconn(int sig);
  236. SIGNAL_TYPE randomsig(int sig);
  237. SIGNAL_TYPE myoob(int sig);
  238. FILE *getdatasock(char *mode),
  239.  *dataconn(char *name, off_t size, char *mode);
  240.  
  241. #ifdef SETPROCTITLE
  242. char **Argv = NULL;             /* pointer to argument vector */
  243. char *LastArgv = NULL;          /* end of argv */
  244. char proctitle[BUFSIZ];         /* initial part of title */
  245.  
  246. #endif /* SETPROCTITLE */
  247.  
  248. #ifdef KERBEROS
  249. void init_krb();
  250. void end_krb();
  251. char krb_ticket_name[100];
  252. #endif /* KERBEROS */
  253.  
  254. #ifdef ULTRIX_AUTH
  255. int ultrix_check_pass(char *passwd, char *xpasswd);
  256. #endif
  257.  
  258. /* ls program commands and options for lreplies on and off */
  259. char  ls_long[50];
  260. char  ls_short[50];
  261. struct aclmember *entry = NULL;
  262.  
  263. #ifdef AMIGA
  264. int kludge = 0;
  265. int amiga_bufsize = (200*512); /* default IO buffer is 100K */
  266. struct muBase *muBase;
  267.  
  268. void
  269. CloseLibs(void)
  270. {
  271.   if(muBase)
  272.     CloseLibrary(muBase);
  273. }
  274. #endif
  275.  
  276. main(int argc, char **argv, char **envp)
  277. {
  278.     int addrlen,
  279.       on = 1;
  280. #ifdef IPTOS_LOWDELAY
  281.     int tos;
  282. #endif
  283.     char *cp;
  284.  
  285. #ifdef AMIGA
  286.     int s = init_inet_daemon();
  287.  
  288.     if (s == -1) {
  289. #ifdef STANDALONE
  290.       struct sockaddr_in sin;
  291.  
  292.       s = serveraccept("ftp", &sin);
  293.       if (s != -1) {
  294.         fprintf(stderr, "Accepted a connection from %s, port %ld\n",
  295.             inet_ntoa(sin.sin_addr), sin.sin_port);
  296.       } else 
  297. #endif
  298.         return 1;
  299.     }
  300.     else
  301.       set_socket_stdio(s);
  302.  
  303.     muBase = (struct muBase *)OpenLibrary(MULTIUSERNAME, MULTIUSERVERSION);
  304.     atexit(&CloseLibs);
  305.  
  306.     /* Check if we are running as root, otherwise fail. */
  307.     if (muBase)
  308.     {
  309.       if (geteuid() != muROOT_UID)
  310.       {
  311.         syslog(LOG_ERR, "not running as root");
  312.         exit(1);
  313.       }
  314.     }
  315. #endif
  316.  
  317. #ifdef SecureWare
  318.     setluid(1);                         /* make sure there is a valid luid */
  319.     set_auth_parameters(argc,argv);
  320.     setreuid(0, 0);
  321. #endif
  322. #if defined(M_UNIX) && !defined(_M_UNIX)
  323.     res_init();                         /* bug in old (1.1.1) resolver     */
  324.     _res.retrans = 20;                  /* because of fake syslog in 3.2.2 */
  325.     setlogmask(LOG_UPTO(LOG_INFO));
  326. #endif
  327.  
  328.     addrlen = sizeof(his_addr);
  329.     if (getpeername(0, (struct sockaddr *) &his_addr, &addrlen) < 0) {
  330.         syslog(LOG_ERR, "getpeername (%s): %m", argv[0]);
  331. #ifndef DEBUG
  332.         exit(1);
  333. #endif
  334.     }
  335.     addrlen = sizeof(ctrl_addr);
  336.     if (getsockname(0, (struct sockaddr *) &ctrl_addr, &addrlen) < 0) {
  337.         syslog(LOG_ERR, "getsockname (%s): %m", argv[0]);
  338. #ifndef DEBUG
  339.         exit(1);
  340. #endif
  341.     }
  342. #ifdef IPTOS_LOWDELAY
  343.     tos = IPTOS_LOWDELAY;
  344.     if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(int)) < 0)
  345.           syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  346. #endif
  347.  
  348.     data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
  349.     debug = 0;
  350.  
  351. #ifdef FACILITY
  352.     openlog("ftpd", LOG_PID | LOG_NDELAY, FACILITY);
  353. #else
  354.     openlog("ftpd", LOG_PID);
  355. #endif
  356.  
  357. #ifdef SETPROCTITLE
  358.     /* Save start and extent of argv for setproctitle. */
  359.     Argv = argv;
  360.     while (*envp)
  361.         envp++;
  362.     LastArgv = envp[-1] + strlen(envp[-1]);
  363. #endif /* SETPROCTITLE */
  364.  
  365.     argc--, argv++;
  366.     while (argc > 0 && *argv[0] == '-') {
  367.         for (cp = &argv[0][1]; *cp; cp++)
  368.             switch (*cp) {
  369.  
  370.             case 'a':
  371.                 use_accessfile = 1;
  372.                 break;
  373.  
  374.             case 'A':
  375.                 use_accessfile = 0;
  376.                 break;
  377.  
  378.             case 'v':
  379.                 debug = 1;
  380.                 break;
  381.  
  382.             case 'd':
  383.                 debug = 1;
  384.                 break;
  385.  
  386.             case 'l':
  387.                 logging = 1;
  388.                 break;
  389.  
  390.             case 'L':
  391.                 log_commands = 1;
  392.                 break;
  393.  
  394.             case 'i':
  395.                 log_incoming_xfers = 1;
  396.                 break;
  397.  
  398.             case 'o':
  399.                 log_outbound_xfers = 1;
  400.                 break;
  401.  
  402.             case 't':
  403.                 timeout = atoi(++cp);
  404.                 if (maxtimeout < timeout)
  405.                     maxtimeout = timeout;
  406.                 goto nextopt;
  407.  
  408. #ifdef AMIGA
  409.             case 'b':
  410.                 amiga_bufsize = (atoi(++cp) * 512);
  411.                 goto nextopt;
  412.  
  413.             case 'k':
  414.                 kludge = 1;
  415.                 goto nextopt;
  416. #endif
  417.  
  418.             case 'T':
  419.                 maxtimeout = atoi(++cp);
  420.                 if (timeout > maxtimeout)
  421.                     timeout = maxtimeout;
  422.                 goto nextopt;
  423.  
  424.             case 'u':
  425.                 {
  426.                     int val = 0;
  427.  
  428.                     while (*++cp && *cp >= '0' && *cp <= '9')
  429.                         val = val * 8 + *cp - '0';
  430.                     if (*cp)
  431.                         fprintf(stderr, "ftpd: Bad value for -u\n");
  432.                     else
  433.                         defumask = val;
  434.                     goto nextopt;
  435.                 }
  436.  
  437.             default:
  438.                 fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n",
  439.                         *cp);
  440.                 break;
  441.             }
  442.       nextopt:
  443.         argc--, argv++;
  444.     }
  445.     (void) freopen(_PATH_DEVNULL, "w", stderr);
  446.  
  447.     /* Checking for random signals ... */
  448. #ifdef SIGHUP
  449.     (void) signal(SIGHUP, randomsig);
  450. #endif
  451. #ifdef SIGINT
  452.     (void) signal(SIGINT, randomsig);
  453. #endif
  454. #ifdef SIGQUIT
  455.     (void) signal(SIGQUIT, randomsig);
  456. #endif
  457. #ifdef SIGILL
  458.     (void) signal(SIGILL, randomsig);
  459. #endif
  460. #ifdef SIGTRAP
  461.     (void) signal(SIGTRAP, randomsig);
  462. #endif
  463. #ifdef SIGIOT
  464.     (void) signal(SIGIOT, randomsig);
  465. #endif
  466. #ifdef SIGEMT
  467.     (void) signal(SIGEMT, randomsig);
  468. #endif
  469. #ifdef SIGFPE
  470.     (void) signal(SIGFPE, randomsig);
  471. #endif
  472. #ifdef SIGKILL
  473.     (void) signal(SIGKILL, randomsig);
  474. #endif
  475. #ifdef SIGBUS
  476.     (void) signal(SIGBUS, randomsig);
  477. #endif
  478. #ifdef SIGSEGV
  479.     (void) signal(SIGSEGV, randomsig);
  480. #endif
  481. #ifdef SIGSYS
  482.     (void) signal(SIGSYS, randomsig);
  483. #endif
  484. #ifdef SIGALRM
  485.     (void) signal(SIGALRM, randomsig);
  486. #endif
  487. #ifdef SIGSTOP
  488.     (void) signal(SIGSTOP, randomsig);
  489. #endif
  490. #ifdef SIGTSTP
  491.     (void) signal(SIGTSTP, randomsig);
  492. #endif
  493. #ifdef SIGTTIN
  494.     (void) signal(SIGTTIN, randomsig);
  495. #endif
  496. #ifdef SIGTTOU
  497.     (void) signal(SIGTTOU, randomsig);
  498. #endif
  499. #ifdef SIGIO
  500.     (void) signal(SIGIO, randomsig);
  501. #endif
  502. #ifdef SIGXCPU
  503.     (void) signal(SIGXCPU, randomsig);
  504. #endif
  505. #ifdef SIGXFSZ
  506.     (void) signal(SIGXFSZ, randomsig);
  507. #endif
  508. #ifdef SIGWINCH
  509.     (void) signal(SIGWINCH, randomsig);
  510. #endif
  511. #ifdef SIGVTALRM
  512.     (void) signal(SIGVTALRM, randomsig);
  513. #endif
  514. #ifdef SIGPROF
  515.     (void) signal(SIGPROF, randomsig);
  516. #endif
  517. #ifdef SIGUSR1
  518.     (void) signal(SIGUSR1, randomsig);
  519. #endif
  520. #ifdef SIGUSR2
  521.     (void) signal(SIGUSR2, randomsig);
  522. #endif
  523.  
  524. #ifdef SIGPIPE
  525.     (void) signal(SIGPIPE, lostconn);
  526. #endif
  527. #ifdef SIGCHLD
  528.     (void) signal(SIGCHLD, SIG_IGN);
  529. #endif
  530.  
  531. #ifdef SIGURG
  532.     if ((int) signal(SIGURG, myoob) < 0)
  533.         syslog(LOG_ERR, "signal: %m");
  534. #endif
  535.  
  536.     /* Try to handle urgent data inline */
  537. #ifdef SO_OOBINLINE
  538.     if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(int)) < 0)
  539.         syslog(LOG_ERR, "setsockopt (SO_OOBINLINE): %m");
  540. #endif
  541.  
  542. #ifdef  F_SETOWN
  543.     if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
  544.         syslog(LOG_ERR, "fcntl F_SETOWN: %m");
  545. #endif
  546.     dolog(&his_addr);
  547.     /* Set up default state */
  548.     data = -1;
  549.     type = TYPE_A;
  550.     form = FORM_N;
  551.     stru = STRU_F;
  552.     mode = MODE_S;
  553.     tmpline[0] = '\0';
  554.  
  555. #ifdef HAVE_SYSINFO
  556.     sysinfo(SI_HOSTNAME, hostname, sizeof (hostname));
  557. #else
  558.     (void) gethostname(hostname, sizeof (hostname));
  559. #endif
  560.  
  561.     access_init();
  562.     authenticate();
  563.     conv_init();
  564.  
  565.     if (is_shutdown(1) != 0) {
  566.         syslog(LOG_INFO, "connection refused (server shut down) from %s [%s]",
  567.                remotehost, remoteaddr);
  568.         reply(500, "%s FTP server shut down -- please try again later.",
  569.               hostname);
  570.         exit(0);
  571.     }
  572.     show_banner(220);
  573.  
  574.     entry = (struct aclmember *) NULL;
  575.     if (getaclentry("lslong", &entry) && ARG0 && strlen(ARG0) > 0) {
  576.           strcpy(ls_long,ARG0);
  577.       if (ARG1 && strlen(ARG1)) {
  578.              strcat(ls_long," ");
  579.          strcat(ls_long,ARG1);
  580.           }
  581.     } else {
  582. #ifdef AMIGA
  583.           strcpy(ls_long,"AmiTCP:bin/ls -lgA");
  584. #else
  585. #ifdef SVR4
  586. #ifndef AIX
  587.           strcpy(ls_long,"/bin/ls -la");
  588. #else
  589.           strcpy(ls_long,"/bin/ls -lA");
  590. #endif
  591. #else
  592.           strcpy(ls_long,"/bin/ls -lgA");
  593. #endif
  594. #endif
  595.     }
  596.     strcat(ls_long," %s");
  597.  
  598.     entry = (struct aclmember *) NULL;
  599.     if (getaclentry("lsshort", &entry) && ARG0 && strlen(ARG0) > 0) {
  600.           strcpy(ls_short,ARG0);
  601.       if (ARG1 && strlen(ARG1)) {
  602.              strcat(ls_short," ");
  603.              strcat(ls_short,ARG1);
  604.       }
  605.     } else {
  606. #ifdef AMIGA
  607.           strcpy(ls_short,"AmiTCP:bin/ls -lgA");
  608. #else
  609. #ifdef SVR4
  610. #ifndef AIX
  611.           strcpy(ls_short,"/bin/ls -la");
  612. #else
  613.           strcpy(ls_short,"/bin/ls -lA");
  614. #endif
  615. #else
  616.           strcpy(ls_short,"/bin/ls -lgA");
  617. #endif
  618. #endif
  619.     }
  620.     strcat(ls_short," %s");
  621.  
  622.     reply(220, "%s FTP server (%s) ready.", hostname, version);
  623.     (void) setjmp(errcatch);
  624.  
  625.     for (;;)
  626.         (void) yyparse();
  627.     /* NOTREACHED */
  628. }
  629.  
  630. SIGNAL_TYPE
  631. randomsig(int sig)
  632. {
  633.     syslog(LOG_ERR, "exiting on signal %d", sig);
  634. #ifndef AMIGA
  635.     chdir("/etc/tmp");
  636. #endif
  637. #ifdef SIGIOT
  638.     signal(SIGIOT, SIG_DFL);
  639. #endif
  640.     signal(SIGILL, SIG_DFL);
  641.     abort();
  642.     /* dologout(-1); *//* NOTREACHED */
  643. }
  644.  
  645. SIGNAL_TYPE
  646. lostconn(int sig)
  647. {
  648.     if (debug)
  649.         syslog(LOG_DEBUG, "lost connection to %s [%s]", remotehost, remoteaddr);
  650.     dologout(-1);
  651. }
  652.  
  653. static char ttyline[20];
  654.  
  655. /* Helper function for sgetpwnam(). */
  656. char *
  657. sgetsave(char *s)
  658. {
  659.     char *new;
  660.     
  661.     new = (char *) malloc(strlen(s) + 1);
  662.  
  663.     if (new == NULL) {
  664.         perror_reply(421, "Local resource failure: malloc");
  665.         dologout(1);
  666.         /* NOTREACHED */
  667.     }
  668.     (void) strcpy(new, s);
  669.     return (new);
  670. }
  671.  
  672. /* Save the result of a getpwnam.  Used for USER command, since the data
  673.  * returned must not be clobbered by any other command (e.g., globbing). */
  674. struct passwd *
  675. sgetpwnam(char *name)
  676. {
  677.     static struct passwd save;
  678.     register struct passwd *p;
  679. #ifdef M_UNIX
  680.     struct passwd *ret = (struct passwd *) NULL;
  681. #endif
  682.     char *sgetsave(char *s);
  683.  
  684. #ifdef KERBEROS
  685.     register struct authorization *q;
  686. #endif /* KERBEROS */
  687.  
  688. #ifdef SecureWare
  689.     struct pr_passwd *pr;
  690. #endif
  691.  
  692. #ifdef KERBEROS
  693.     init_krb();
  694.     q = getauthuid(p->pw_uid);
  695.     end_krb();
  696. #endif /* KERBEROS */
  697.  
  698. #ifdef M_UNIX
  699. # ifdef SecureWare
  700.     if ((pr = getprpwnam(name)) == NULL)
  701.         goto DONE;
  702. # endif /* SecureWare */
  703.     if ((p = getpwnam(name)) == NULL)
  704.         goto DONE;
  705. #else   /* M_UNIX */
  706. # ifdef SecureWare
  707.     if ((pr = getprpwnam(name)) == NULL)
  708.         return((struct passwd *) pr);
  709. # endif /* SecureWare */
  710.     if ((p = getpwnam(name)) == NULL)
  711.         return (p);
  712. #endif  /* M_UNIX */
  713.  
  714.     if (save.pw_name)   free(save.pw_name);
  715.     if (save.pw_gecos)  free(save.pw_gecos);
  716.     if (save.pw_dir)    free(save.pw_dir);
  717.     if (save.pw_shell)  free(save.pw_shell);
  718.  
  719.     save = *p;
  720.  
  721.     save.pw_name = sgetsave(p->pw_name);
  722.  
  723. #ifdef KERBEROS
  724.     save.pw_passwd = sgetsave(q->a_password);
  725. #elif defined(SecureWare)
  726.      if (pr->uflg.fg_encrypt && pr->ufld.fd_encrypt && *pr->ufld.fd_encrypt)
  727.         save.pw_passwd = sgetsave(pr->ufld.fd_encrypt);
  728.      else
  729.         save.pw_passwd = sgetsave("");
  730. #else
  731.     save.pw_passwd = sgetsave(p->pw_passwd);
  732. #endif
  733.  
  734.     save.pw_gecos = sgetsave(p->pw_gecos);
  735.     save.pw_dir = sgetsave(p->pw_dir);
  736.     save.pw_shell = sgetsave(p->pw_shell);
  737. #ifdef M_UNIX
  738.     ret = &save;
  739. DONE:
  740.     endpwent();
  741. #endif
  742. #ifdef SecureWare
  743.     endprpwent();
  744. #endif
  745. #ifdef M_UNIX
  746.     return(ret);
  747. #else
  748.     return(&save);
  749. #endif
  750. }
  751.  
  752. #ifdef AMIGA
  753. char *amigausername;
  754. #endif
  755.  
  756. int login_attempts;             /* number of failed login attempts */
  757. int askpasswd;                  /* had user command, ask for passwd */
  758.  
  759. /* USER command. Sets global passwd pointer pw if named account exists and is
  760.  * acceptable; sets askpasswd if a PASS command is expected.  If logged in
  761.  * previously, need to reset state.  If name is "ftp" or "anonymous", the
  762.  * name is not in _PATH_FTPUSERS, and ftp account exists, set anonymous and
  763.  * pw, then just return.  If account doesn't exist, ask for passwd anyway.
  764.  * Otherwise, check user requesting login privileges.  Disallow anyone who
  765.  * does not have a standard shell as returned by getusershell().  Disallow
  766.  * anyone mentioned in the file _PATH_FTPUSERS to allow people such as root
  767.  * and uucp to be avoided. */
  768. user(char *name)
  769. {
  770.     register char *cp;
  771.     char *shell;
  772.     char *getusershell();
  773.     int   why = 0;
  774.  
  775. #ifdef AMIGA
  776.     /* We need to save the username because we will
  777.      * use it later in muLoginA() and CheckAccess().
  778.      */
  779.     if(amigausername)
  780.       free(amigausername);
  781.     if(amigausername = malloc(strcmp ("anonymous", name) ? (strlen(name) + 1) : 4))
  782.       strcpy(amigausername, strcmp ("anonymous", name) ? name : "ftp");
  783.     else
  784.     {
  785.         perror_reply(421, "Local resource failure: malloc");
  786.         return;
  787.     }
  788. #endif
  789.  
  790. #ifdef HOST_ACCESS                     /* 19-Mar-93    BM              */
  791.     if (!rhost_ok(name, remotehost, remoteaddr))
  792.     {
  793.             reply(530, "User %s access denied.", name);
  794.             syslog(LOG_NOTICE,
  795.                     "FTP LOGIN REFUSED (name in %s) FROM %s [%s], %s",
  796.                      _PATH_FTPHOSTS, remotehost, remoteaddr, name);
  797.             return;
  798.     }
  799. #endif
  800.  
  801. #ifdef LOG_FAILED                       /* 06-Nov-92    EHK             */
  802.     strncpy(the_user, name, MAXUSERNAMELEN - 1);
  803. #endif
  804.  
  805.     if (logged_in) {
  806.         if (anonymous || guest) {
  807.             reply(530, "Can't change user from guest login.");
  808.             return;
  809.         }
  810.         end_login();
  811.     }
  812.  
  813.     anonymous = 0;
  814.     acl_remove();
  815.  
  816.     if (!strcasecmp(name, "ftp") || !strcasecmp(name, "anonymous")) {
  817.       struct aclmember *entry = NULL;
  818.       int machineok=1;
  819.       char guestservername[MAXHOSTNAMELEN];
  820.       guestservername[0]='\0';
  821.  
  822.       if (checkuser("ftp") || checkuser("anonymous")) {
  823.           reply(530, "User %s access denied.", name);
  824.           syslog(LOG_NOTICE,
  825. #ifndef AMIGA
  826.            "FTP LOGIN REFUSED (ftp in /etc/ftpusers) FROM %s [%s], %s",
  827. #else
  828.            "FTP LOGIN REFUSED (ftp in AmiTCP:db/ftpusers) FROM %s [%s], %s",
  829. #endif
  830.            remotehost, remoteaddr, name);
  831.           return;
  832.           
  833.         /*
  834.         ** Algorithm used:
  835.         ** - if no "guestserver" directive is present,
  836.         **     anonymous access is allowed, for backward compatibility.
  837.         ** - if a "guestserver" directive is present,
  838.         **     anonymous access is restricted to the machines listed,
  839.         **     usually the machine whose CNAME on the current domain
  840.         **     is "ftp"...
  841.         **
  842.         ** the format of the "guestserver" line is
  843.         ** guestserver [<machine1> [<machineN>]]
  844.         ** that is, "guestserver" will forbid anonymous access on all machines
  845.         ** while "guestserver ftp inf" will allow anonymous access on
  846.         ** the two machines whose CNAMES are "ftp.enst.fr" and "inf.enst.fr".
  847.         **
  848.         ** if anonymous access is denied on the current machine,
  849.         ** the user will be asked to use the first machine listed (if any)
  850.         ** on the "guestserver" line instead:
  851.         ** 530- Guest login not allowed on this machine,
  852.         **      connect to ftp.enst.fr instead.
  853.         **
  854.         ** -- <Nicolas.Pioch@enst.fr>
  855.         */
  856.       } else if (getaclentry("guestserver", &entry)
  857.                  && ARG0 && strlen(ARG0) > 0) {
  858.         struct hostent *tmphostent;
  859.  
  860.         /*
  861.         ** if a "guestserver" line is present,
  862.         ** default is not to allow guest logins
  863.         */
  864.         machineok=0;
  865.  
  866.         if (hostname[0]
  867.             && ((tmphostent=gethostbyname(hostname)))) {
  868.  
  869.           /*
  870.           ** hostname is the only first part of the FQDN
  871.           ** this may or may not correspond to the h_name value
  872.           ** (machines with more than one IP#, CNAMEs...)
  873.           ** -> need to fix that, calling gethostbyname on hostname
  874.           **
  875.           ** WARNING!
  876.           ** for SunOS 4.x, you need to have a working resolver in the libc
  877.           ** for CNAMES to work properly.
  878.           ** If you don't, add "-lresolv" to the libraries before compiling!
  879.           */
  880.           char dns_localhost[MAXHOSTNAMELEN];
  881.           int machinecount;
  882.  
  883.           strncpy(dns_localhost,
  884.                   tmphostent->h_name,
  885.                   sizeof(dns_localhost));
  886.           dns_localhost[sizeof(dns_localhost)-1]='\0';
  887.  
  888.           for (machinecount=0;
  889.                entry->arg[machinecount] && (entry->arg[machinecount])[0];
  890.                machinecount++) {
  891.  
  892.             if ((tmphostent=gethostbyname(entry->arg[machinecount]))) {
  893.               /*
  894.               ** remember the name of the first machine for redirection
  895.               */
  896.  
  897.               if ((!machinecount) && tmphostent->h_name) {
  898.                 strncpy(guestservername, entry->arg[machinecount],
  899.                         sizeof(guestservername));
  900.                 guestservername[sizeof(guestservername)-1]='\0';
  901.               }
  902.  
  903.               if (!strcasecmp(tmphostent->h_name, dns_localhost)) {
  904.                 machineok++;
  905.                 break;
  906.               }
  907.             }
  908.           }
  909.         }
  910.       }
  911.       if (!machineok) {
  912.         if (guestservername[0])
  913.           reply(530,
  914.              "Guest login not allowed on this machine, connect to %s instead.",
  915.                 guestservername);
  916.         else
  917.           reply(530,
  918.                 "Guest login not allowed on this machine.");
  919.         syslog(LOG_NOTICE,
  920.                "FTP LOGIN REFUSED (localhost not in guestservers) FROM %s [%s], %s",
  921.                remotehost, remoteaddr, name);
  922.         /* End of the big patch -- Nap */
  923.  
  924.         } else if ((pw = sgetpwnam("ftp")) != NULL) {
  925.             anonymous = 1;      /* for the access_ok call */
  926.             if ((why = access_ok(530)) == 1) {
  927.                 askpasswd = 1;
  928.                 acl_setfunctions();
  929.                 reply(331, "Guest login ok, send your complete e-mail address as password.");
  930.             } else if (why == 0) {
  931.                 reply(530, "User %s access denied..", name);
  932.                 syslog(LOG_NOTICE,
  933.                        "FTP LOGIN REFUSED (access denied) FROM %s [%s], %s",
  934.                        remotehost, remoteaddr, name);
  935.                 anonymous = 0;
  936.             } else {
  937.                 reply(530, "User %s access denied.", name);
  938.                 syslog(LOG_NOTICE,
  939.                        "FTP LOGIN REFUSED (access denied) FROM %s [%s], %s",
  940.                        remotehost, remoteaddr, name);
  941.                 dologout(0);
  942.             }
  943.         } else {
  944.             reply(530, "User %s unknown.", name);
  945.             syslog(LOG_NOTICE,
  946. #ifndef AMIGA
  947.               "FTP LOGIN REFUSED (ftp not in /etc/passwd) FROM %s [%s], %s",
  948. #else
  949.               "FTP LOGIN REFUSED (ftp not in AmiTCP:db/passwd) FROM %s [%s], %s",
  950. #endif
  951.                    remotehost, remoteaddr, name);
  952.         }
  953.         return;
  954.     }
  955.     if ((pw = sgetpwnam(name)) != NULL) {
  956.         if ((shell = pw->pw_shell) == NULL || *shell == 0)
  957.             shell = _PATH_BSHELL;
  958.         while ((cp = getusershell()) != NULL)
  959.             if (strcmp(cp, shell) == 0)
  960.                 break;
  961.         endusershell();
  962.         if (cp == NULL || checkuser(name)) {
  963.             reply(530, "User %s access denied...", name);
  964.             if (logging)
  965.                 syslog(LOG_NOTICE,
  966.                        "FTP LOGIN REFUSED (bad shell) FROM %s [%s], %s",
  967.                        remotehost, remoteaddr, name);
  968.             pw = (struct passwd *) NULL;
  969.             return;
  970.         }
  971.         /* if user is a member of any of the guestgroups, cause a chroot() */
  972.         /* after they log in successfully                                  */
  973.         guest = acl_guestgroup(pw);
  974.     }
  975.     if (access_ok(530) < 1) {
  976.         reply(530, "User %s access denied....", name);
  977.         syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s [%s], %s",
  978.                remotehost, remoteaddr, name);
  979.         return;
  980.     } else
  981.         acl_setfunctions();
  982.  
  983.     reply(331, "Password required for %s.", name);
  984.     askpasswd = 1;
  985.     /* Delay before reading passwd after first failed attempt to slow down
  986.      * passwd-guessing programs. */
  987.     if (login_attempts)
  988.         sleep((unsigned) login_attempts);
  989. }
  990.  
  991. /* Check if a user is in the file _PATH_FTPUSERS */
  992. checkuser(char *name)
  993. {
  994.     register FILE *fd;
  995.     register char *p;
  996.     char line[BUFSIZ];
  997.  
  998.     if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {
  999.         while (fgets(line, sizeof(line), fd) != NULL)
  1000.             if ((p = strchr(line, '\n')) != NULL) {
  1001.                 *p = '\0';
  1002.                 if (line[0] == '#')
  1003.                     continue;
  1004.                 if (strcmp(line, name) == 0) {
  1005.                     (void) fclose(fd);
  1006.                     return (1);
  1007.                 }
  1008.             }
  1009.         (void) fclose(fd);
  1010.     }
  1011.     return (0);
  1012. }
  1013.  
  1014. /* Terminate login as previous user, if any, resetting state; used when USER
  1015.  * command is given or login fails. */
  1016. end_login(void)
  1017. {
  1018.     (void) seteuid((uid_t) 0);
  1019.     if (logged_in)
  1020.         logwtmp(ttyline, "", "");
  1021.     pw = NULL;
  1022.     logged_in = 0;
  1023.     anonymous = 0;
  1024.     guest = 0;
  1025. }
  1026.  
  1027. int
  1028. validate_eaddr(char *eaddr)
  1029. {
  1030.     int i,
  1031.       host,
  1032.       state;
  1033.  
  1034.     for (i = host = state = 0; eaddr[i] != '\0'; i++) {
  1035.         switch (eaddr[i]) {
  1036.         case '.':
  1037.             if (!host)
  1038.                 return 0;
  1039.             if (state == 2)
  1040.                 state = 3;
  1041.             host = 0;
  1042.             break;
  1043.         case '@':
  1044.             if (!host || state > 1 || !strncasecmp("ftp", eaddr + i - host, host))
  1045.                 return 0;
  1046.             state = 2;
  1047.             host = 0;
  1048.             break;
  1049.         case '!':
  1050.         case '%':
  1051.             if (!host || state > 1)
  1052.                 return 0;
  1053.             state = 1;
  1054.             host = 0;
  1055.             break;
  1056.         case '-':
  1057.             break;
  1058.         default:
  1059.             host++;
  1060.         }
  1061.     }
  1062.     if (((state == 3) && host > 1) || ((state == 2) && !host) ||
  1063.         ((state == 1) && host > 1))
  1064.         return 1;
  1065.     else
  1066.         return 0;
  1067. }
  1068.  
  1069. pass(char *passwd)
  1070. {
  1071.     char *xpasswd,
  1072.      *salt;
  1073.  
  1074. #ifdef AMIGA
  1075.     int passok = FALSE;
  1076. #endif
  1077.  
  1078. #ifdef ULTRIX_AUTH
  1079.     int numfails;
  1080. #endif /* ULTRIX_AUTH */
  1081.  
  1082.     if (logged_in || askpasswd == 0) {
  1083.         reply(503, "Login with USER first.");
  1084.         return;
  1085.     }
  1086.     askpasswd = 0;
  1087.  
  1088.     /* Disable lreply() if the first character of the password is '-' since
  1089.      * some hosts don't understand continuation messages and hang... */
  1090.  
  1091.     if (*passwd == '-')
  1092.         dolreplies = 0;
  1093.     else
  1094.         dolreplies = 1;
  1095.  
  1096.     if (!anonymous) {           /* "ftp" is only account allowed no password */
  1097.         if (*passwd == '-')
  1098.             passwd++;
  1099. #ifdef SHADOW_PASSWORD
  1100.         if (pw) {
  1101.            struct spwd *spw = getspnam( pw->pw_name );
  1102.            if( !spw ) { pw->pw_passwd = ""; }
  1103.            else { pw->pw_passwd = spw->sp_pwdp; }
  1104.         }
  1105. #endif
  1106.  
  1107. #ifdef AMIGA
  1108.         if(!muBase) {
  1109. #endif
  1110.         *guestpw = NULL;
  1111.         if (pw == NULL)
  1112.             salt = "xx";
  1113.         else
  1114.             salt = pw->pw_passwd;
  1115. #ifdef AMIGA
  1116.         }
  1117. #endif
  1118. #ifdef KERBEROS
  1119.         xpasswd = crypt16(passwd, salt);
  1120. #else
  1121. #ifdef AMIGA
  1122.         if(!muBase)
  1123. #endif
  1124.         xpasswd = crypt(passwd, salt);
  1125. #endif
  1126.  
  1127. #ifdef ULTRIX_AUTH
  1128.         if ((numfails = ultrix_check_pass(passwd, xpasswd)) < 0) {
  1129. #else
  1130. #ifndef AMIGA
  1131.         /* The strcmp does not catch null passwords! */
  1132.         if (pw == NULL || *pw->pw_passwd == '\0' ||
  1133.             strcmp(xpasswd, pw->pw_passwd)) {
  1134. #else
  1135.         if (muBase) {
  1136.           if (seteuid(pw->pw_uid) >= 0) {
  1137.             ULONG tags[3];
  1138.  
  1139.             tags[0] = muT_Password;
  1140.             tags[1] = (ULONG)passwd;
  1141.             tags[2] = TAG_END;
  1142.             passok = muCheckPasswd(tags) && *passwd != '\0';
  1143.             seteuid(0);
  1144.           }
  1145.         } else {
  1146.           passok = (pw != NULL && *pw->pw_passwd != '\0' &&
  1147.                     !strcmp(xpasswd, pw->pw_passwd));
  1148.         }
  1149.         if(!passok) {
  1150. #endif
  1151. #endif
  1152.             reply(530, "Login incorrect.");
  1153.  
  1154. #ifdef LOG_FAILED                       /* 27-Apr-93    EHK/BM             */
  1155.             syslog(LOG_INFO, "failed login from %s [%s], %s",
  1156.                               remotehost, remoteaddr, the_user);
  1157. #endif
  1158.             acl_remove();
  1159.  
  1160.             pw = NULL;
  1161.             if (++login_attempts >= lgi_failure_threshold) {
  1162.                 syslog(LOG_NOTICE, "repeated login failures from %s [%s]",
  1163.                        remotehost, remoteaddr);
  1164.                 exit(0);
  1165.             }
  1166.             return;
  1167.         }
  1168.     } else {
  1169.         char *pwin,
  1170.          *pwout = guestpw;
  1171.         struct aclmember *entry = NULL;
  1172.         int valid;
  1173.  
  1174.         if (getaclentry("passwd-check", &entry) &&
  1175.             ARG0 && strcasecmp(ARG0, "none")) {
  1176.  
  1177.             if (!strcasecmp(ARG0, "rfc822"))
  1178.                 valid = validate_eaddr(passwd);
  1179.             else if (!strcasecmp(ARG0, "trivial"))
  1180.                 valid = (strchr(passwd, '@') == NULL) ? 0 : 1;
  1181.             else
  1182.                 valid = 1;
  1183.  
  1184.             if (!valid && ARG1 && !strcasecmp(ARG1, "enforce")) {
  1185.                 lreply(530, "The response '%s' is not valid", passwd);
  1186.                 lreply(530, "Please use your e-mail address as your password");
  1187.                 lreply(530, "   for example: %s@%s or %s@",
  1188.                        authenticated ? authuser : "joe", remotehost,
  1189.                        authenticated ? authuser : "joe");
  1190.                 lreply(530, "[%s will be added if password ends with @]",
  1191.                        remotehost);
  1192.                 reply(530, "Login incorrect.");
  1193.         acl_remove();    
  1194.                 if (++login_attempts >= lgi_failure_threshold) {
  1195.                     syslog(LOG_NOTICE, "repeated login failures from %s [%s]",
  1196.                            remotehost, remoteaddr);
  1197.                     exit(0);
  1198.                 }
  1199.                 return;
  1200.             } else if (!valid) {
  1201.                 lreply(230, "The response '%s' is not valid", passwd);
  1202.                 lreply(230,
  1203.                 "Next time please use your e-mail address as your password");
  1204.                 lreply(230, "        for example: %s@%s",
  1205.                        authenticated ? authuser : "joe", remotehost);
  1206.             }
  1207.         }
  1208.         if (!*passwd) {
  1209.             strcpy(guestpw, "[none_given]");
  1210.         } else {
  1211.             int cnt = sizeof(guestpw) - 2;
  1212.  
  1213.             for (pwin = passwd; *pwin && cnt--; pwin++)
  1214.                 if (!isgraph(*pwin))
  1215.                     *pwout++ = '_';
  1216.                 else
  1217.                     *pwout++ = *pwin;
  1218.         }
  1219.     }
  1220.  
  1221.     /* if autogroup command applies to user's class change pw->pw_gid */
  1222.     if (anonymous)
  1223.         (void) acl_autogroup(pw);
  1224.  
  1225.     login_attempts = 0;         /* this time successful */
  1226.     (void) setegid((gid_t) pw->pw_gid);
  1227.     (void) initgroups(pw->pw_name, pw->pw_gid);
  1228.  
  1229.     /* open wtmp before chroot */
  1230.     (void) sprintf(ttyline, "ftp%d", getpid());
  1231.     logwtmp(ttyline, pw->pw_name, remotehost);
  1232.     logged_in = 1;
  1233.  
  1234.     /* if logging is enabled, open logfile before chroot */
  1235.     if (log_outbound_xfers || log_incoming_xfers)
  1236.         xferlog = open(_PATH_XFERLOG, O_WRONLY | O_APPEND | O_CREAT, 0660);
  1237.  
  1238.     expand_id();
  1239.  
  1240.     if (anonymous || guest) {
  1241.         /* We MUST do a chdir() after the chroot. Otherwise the old current
  1242.          * directory will be accessible as "." outside the new root! */
  1243.         if (anonymous) {
  1244. #ifdef AMIGA
  1245.             if (chroot(pw->pw_dir) < 0 || chdir(pw->pw_dir) < 0) {
  1246. #else
  1247.             if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
  1248. #endif
  1249.                 reply(550, "Can't set guest privileges.");
  1250.                 goto bad;
  1251.             }
  1252.         } else if (guest) {
  1253. #ifndef AMIGA
  1254.             char *sp;
  1255.  
  1256.             /* determine root and home directory */
  1257.             if ((sp = strstr(pw->pw_dir, "/./")) == NULL) {
  1258.                 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
  1259.                     reply(550, "Can't set guest privileges.");
  1260.                     goto bad;
  1261.                 }
  1262.             } else {
  1263.                 *sp++ = '\0';
  1264.  
  1265.                 if (chroot(pw->pw_dir) < 0 || chdir(++sp) < 0) {
  1266.                     reply(550, "Can't set guest privileges.");
  1267.                     goto bad;
  1268.                 }
  1269.             }
  1270. #else
  1271.             if (chroot(pw->pw_dir) < 0 || chdir(pw->pw_dir) < 0) {
  1272.                 reply(550, "Can't set guest privileges.");
  1273.                 goto bad;
  1274.             }
  1275. #endif
  1276.         }
  1277.     } else {
  1278.         if (chdir(pw->pw_dir) < 0) {
  1279. #ifdef AMIGA
  1280.             if (chdir("SYS:") < 0) {
  1281. #else
  1282.             if (chdir("/") < 0) {
  1283. #endif
  1284.                 reply(530, "User %s: can't change directory to %s.",
  1285.                       pw->pw_name, pw->pw_dir);
  1286.                 goto bad;
  1287.             } else
  1288. #ifndef AMIGA
  1289.                 lreply(230, "No directory! Logging in with home=/");
  1290. #else
  1291.                 lreply(230, "No directory! Logging in with home=SYS:");
  1292. #endif
  1293.         }
  1294.     }
  1295.  
  1296. #ifdef AIX
  1297.     {
  1298.        /* AIX 3 lossage.  Don't ask.  It's undocumented.  */
  1299.        priv_t priv;
  1300.  
  1301.        priv.pv_priv[0] = 0;
  1302.        priv.pv_priv[1] = 0;
  1303.        setgroups(NULL, NULL);
  1304.        if (setpriv(PRIV_SET|PRIV_INHERITED|PRIV_EFFECTIVE|PRIV_BEQUEATH,
  1305.                    &priv, sizeof(priv_t)) < 0 ||
  1306.            setuidx(ID_REAL|ID_EFFECTIVE, (uid_t)pw->pw_uid) < 0 ||
  1307.            seteuid((uid_t)pw->pw_uid) < 0) {
  1308.                reply(550, "Can't set uid (AIX3).");
  1309.                goto bad;
  1310.        }
  1311.     }
  1312. # ifdef UID_DEBUG
  1313.     lreply(230, "ruid=%d, euid=%d, suid=%d, luid=%d", getuidx(ID_REAL),
  1314.          getuidx(ID_EFFECTIVE), getuidx(ID_SAVED), getuidx(ID_LOGIN));
  1315.     lreply(230, "rgid=%d, egid=%d, sgid=%d, lgid=%d", getgidx(ID_REAL),
  1316.          getgidx(ID_EFFECTIVE), getgidx(ID_SAVED), getgidx(ID_LOGIN));
  1317. #endif
  1318. #else
  1319.     if (seteuid((uid_t) pw->pw_uid) < 0) {
  1320.         reply(550, "Can't set uid.");
  1321.         goto bad;
  1322.     }
  1323. #endif
  1324.     /* * following two lines were inside the next scope... */
  1325.  
  1326.     show_message(230, LOG_IN);
  1327.     show_readme(230, LOG_IN);
  1328.  
  1329. #ifdef ULTRIX_AUTH
  1330.     if (!anonymous && numfails > 0) {
  1331.         lreply(230,
  1332.             "There have been %d unsuccessful login attempts on your account",
  1333.             numfails);
  1334.     }
  1335. #endif /* ULTRIX_AUTH */    
  1336.  
  1337.     if (anonymous) {
  1338.         (void) is_shutdown(0);  /* display any shutdown messages now */
  1339.  
  1340.         reply(230, "Guest login ok, access restrictions apply.");
  1341. #ifdef SETPROCTITLE
  1342.         sprintf(proctitle, "%s: anonymous/%.*s", remotehost,
  1343.                     sizeof(proctitle) - sizeof(remotehost) -
  1344.                     sizeof(": anonymous/"), passwd);
  1345.         setproctitle("%s", proctitle);
  1346. #endif /* SETPROCTITLE */
  1347.         if (logging)
  1348.             syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s [%s], %s",
  1349.                    remotehost, remoteaddr, passwd);
  1350.     } else {
  1351.         reply(230, "User %s logged in.%s", pw->pw_name, guest ?
  1352.               "  Access restrictions apply." : "");
  1353. #ifdef SETPROCTITLE
  1354.         sprintf(proctitle, "%s: %s", remotehost, pw->pw_name);
  1355.         setproctitle(proctitle);
  1356. #endif /* SETPROCTITLE */
  1357.         if (logging)
  1358.             syslog(LOG_INFO, "FTP LOGIN FROM %s [%s], %s",
  1359.                    remotehost, remoteaddr, pw->pw_name);
  1360.     }
  1361.     home = pw->pw_dir;          /* home dir for globbing */
  1362.     (void) umask(defumask);
  1363.     return;
  1364.   bad:
  1365.     /* Forget all about it... */
  1366.     xferlog = 0;
  1367.     end_login();
  1368. }
  1369.  
  1370. char *
  1371. opt_string(int options)
  1372. {
  1373.     static char buf[100];
  1374.     char *ptr = buf;
  1375.  
  1376.     if ((options & O_COMPRESS) != NULL)
  1377.         *ptr++ = 'C';
  1378.     if ((options & O_TAR) != NULL)
  1379.         *ptr++ = 'T';
  1380.     if ((options & O_UNCOMPRESS) != NULL)
  1381.         *ptr++ = 'U';
  1382.     if (options == 0)
  1383.         *ptr++ = '_';
  1384.     *ptr++ = '\0';
  1385.     return (buf);
  1386. }
  1387.  
  1388. retrieve(char *cmd, char *name)
  1389. {
  1390.     FILE *fin,
  1391.      *dout;
  1392.     struct stat st,
  1393.       junk;
  1394.     int (*closefunc) () = NULL;
  1395.     int options = 0;
  1396.     time_t start_time = time(NULL);
  1397.     static char *logname;
  1398.     char namebuf[MAXPATHLEN];
  1399.     struct convert *cptr;
  1400.  
  1401. #ifdef AMIGA
  1402.     /* convert unix path (with ".." and ".") to amiga path */
  1403.     UnixToAmiga(name);
  1404.  
  1405.     /* check if user is allowed to access this directory */
  1406.     if (!CheckAccess(name, FALSE))
  1407.     {
  1408.         errno = EACCES;
  1409.         perror_reply(550, name);
  1410.         return;
  1411.     }
  1412. #endif
  1413.  
  1414.     if (!cmd && stat(name, &st)) {
  1415.         char fnbuf[MAXPATHLEN],
  1416.          *ptr;
  1417.  
  1418.         cptr = cvtptr;
  1419.  
  1420.         if (cptr == NULL) {
  1421.             (void) reply(550, "%s: No such file OR directory.", name);
  1422.             return;
  1423.         }
  1424.  
  1425.         do {
  1426.             if (!(mangleopts & O_COMPRESS) && (cptr->options & O_COMPRESS))
  1427.                 continue;
  1428.             if (!(mangleopts & O_UNCOMPRESS) && (cptr->options & O_UNCOMPRESS))
  1429.                 continue;
  1430.             if (!(mangleopts & O_TAR) && (cptr->options & O_TAR))
  1431.                 continue;
  1432.  
  1433.             if ( (cptr->stripfix) && (cptr->postfix) ) {
  1434.                 int pfxlen = strlen(cptr->postfix);
  1435.         int sfxlen = strlen(cptr->stripfix);
  1436.                 int namelen = strlen(name);
  1437.                 (void) strcpy(fnbuf, name);
  1438.  
  1439.                 if (namelen <= pfxlen)
  1440.                     continue;
  1441.         if ((namelen - pfxlen + sfxlen) >= sizeof(fnbuf))
  1442.             continue;
  1443.  
  1444.         if (strcmp(fnbuf + namelen - pfxlen, cptr->postfix))
  1445.             continue;
  1446.                 *(fnbuf + namelen - pfxlen) = '\0';
  1447.                 (void) strcat(fnbuf, cptr->stripfix);
  1448.                 if (stat(fnbuf, &st))
  1449.                     continue;
  1450.             } else if (cptr->postfix) {
  1451.                 int pfxlen = strlen(cptr->postfix);
  1452.                 int namelen = strlen(name);
  1453.  
  1454.                 if (namelen <= pfxlen)
  1455.                     continue;
  1456.                 (void) strcpy(fnbuf, name);
  1457.                 if (strcmp(fnbuf + namelen - pfxlen, cptr->postfix))
  1458.                     continue;
  1459.                 *(fnbuf + namelen - pfxlen) = (char) NULL;
  1460.                 if (stat(fnbuf, &st))
  1461.                     continue;
  1462.             } else if (cptr->stripfix) {
  1463.                 (void) strcpy(fnbuf, name);
  1464.                 (void) strcat(fnbuf, cptr->stripfix);
  1465.                 if (stat(fnbuf, &st))
  1466.                     continue;
  1467.             } else {
  1468.                 (void) reply(550, "%s: No such file OR directory.", name);
  1469.                 return;
  1470.             }
  1471.  
  1472.             if (S_ISDIR(st.st_mode)) {
  1473.                 if (!(cptr->types & T_DIR)) {
  1474.                     (void) reply(550, "Cannot %s directories.", cptr->name);
  1475.                     return;
  1476.                 }
  1477.                 if (cptr->options & O_TAR) {
  1478.                     strcpy(namebuf, fnbuf);
  1479.                     strcat(namebuf, "/.notar");
  1480.                     if (!stat(namebuf, &junk)) {
  1481.                         (void) reply(550,
  1482.                                   "Sorry, you may not TAR that directory.");
  1483.                         return;
  1484.                     }
  1485.                 }
  1486.             }
  1487.  
  1488.             if (S_ISREG(st.st_mode) && !(cptr->types & T_REG)) {
  1489.                 (void) reply(550, "Cannot %s plain files.", cptr->name);
  1490.                 return;
  1491.             }
  1492.             if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
  1493.                 (void) reply(550, "Cannot %s special files.", cptr->name);
  1494.                 return;
  1495.             }
  1496.             if (!(cptr->types & T_ASCII) && deny_badasciixfer(550, ""))
  1497.                 return;
  1498.  
  1499.             logname = fnbuf;
  1500.             options |= cptr->options;
  1501.  
  1502.             strcpy(namebuf, cptr->external_cmd);
  1503.             if ((ptr = strchr(namebuf, ' ')) != NULL)
  1504.                 *ptr = '\0';
  1505.             if (stat(namebuf, &st) != NULL) {
  1506.                 syslog(LOG_ERR, "external command %s not found",
  1507.                        namebuf);
  1508.                 (void) reply(550,
  1509.                 "Local error: conversion program not found. Cannot %s file.",
  1510.                              cptr->name);
  1511.                 return;
  1512.             }
  1513.             (void) retrieve(cptr->external_cmd, fnbuf);
  1514.  
  1515.             goto dolog;
  1516.         } while ( (cptr = cptr->next) != NULL );
  1517.  
  1518.     } else
  1519.         logname = (char *) NULL;
  1520.  
  1521.     if (cmd == 0) {
  1522.         fin = fopen(name, "r"), closefunc = fclose;
  1523.         st.st_size = 0;
  1524.     } else {
  1525.         char line[BUFSIZ];
  1526.  
  1527.         (void) sprintf(line, cmd, name), name = line;
  1528.         fin = ftpd_popen(line, "r", 1), closefunc = ftpd_pclose;
  1529.         st.st_size = -1;
  1530. #ifdef HAVE_ST_BLKSIZE
  1531.         st.st_blksize = BUFSIZ;
  1532. #endif
  1533.     }
  1534.     if (fin == NULL) {
  1535.         if (errno != 0)
  1536.             perror_reply(550, name);
  1537.         return;
  1538.     }
  1539.     if (cmd == 0 &&
  1540.         (fstat(fileno(fin), &st) < 0 || (st.st_mode & S_IFMT) != S_IFREG)
  1541. #ifdef AMIGA
  1542.         && !kludge
  1543. #endif
  1544.         ) {
  1545.         reply(550, "%s: not a plain file.", name);
  1546.         goto done;
  1547.     }
  1548.     if (restart_point) {
  1549.         if (type == TYPE_A) {
  1550.             register int i,
  1551.               n,
  1552.               c;
  1553.  
  1554.             n = restart_point;
  1555.             i = 0;
  1556.             while (i++ < n) {
  1557.                 if ((c = getc(fin)) == EOF) {
  1558.                     perror_reply(550, name);
  1559.                     goto done;
  1560.                 }
  1561.                 if (c == '\n')
  1562.                     i++;
  1563.             }
  1564.         } else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
  1565.             perror_reply(550, name);
  1566.             goto done;
  1567.         }
  1568.     }
  1569.     dout = dataconn(name, st.st_size, "w");
  1570.     if (dout == NULL)
  1571.         goto done;
  1572. #ifdef HAVE_ST_BLKSIZE
  1573.     send_data(fin, dout, st.st_blksize);
  1574. #else
  1575. #ifndef AMIGA
  1576.     send_data(fin, dout, BUFSIZ);
  1577. #else
  1578.     send_data(fin, dout, amiga_bufsize);
  1579. #endif
  1580. #endif
  1581.     (void) fclose(dout);
  1582.  
  1583.   dolog:
  1584.     if (log_outbound_xfers && xferlog && (cmd == 0)) {
  1585.         char msg[MAXPATHLEN];
  1586.         int xfertime = time(NULL) - start_time;
  1587.         time_t curtime = time(NULL);
  1588.         int loop;
  1589.  
  1590.         if (!xfertime)
  1591.             xfertime++;
  1592.         realpath(logname ? logname : name, namebuf);
  1593.         for (loop = 0; namebuf[loop]; loop++)
  1594.             if (isspace(namebuf[loop]) || iscntrl(namebuf[loop]))
  1595.                 namebuf[loop] = '_';
  1596.         sprintf(msg, "%.24s %d %s %d %s %c %s %c %c %s ftp %d %s\n",
  1597.                 ctime(&curtime),
  1598.                 xfertime,
  1599.                 remotehost,
  1600.                 byte_count,
  1601.                 namebuf,
  1602.                 (type == TYPE_A) ? 'a' : 'b',
  1603.                 opt_string(options),
  1604.                 'o',
  1605.                 anonymous ? 'a' : 'r',
  1606.                 anonymous ? guestpw : pw->pw_name,
  1607.                 authenticated,
  1608.                 authenticated ? authuser : "*"
  1609.             );
  1610.         write(xferlog, msg, strlen(msg));
  1611.     }
  1612.     data = -1;
  1613.     pdata = -1;
  1614.   done:
  1615.     if (closefunc)
  1616.         (*closefunc) (fin);
  1617. }
  1618.  
  1619. store(char *name, char *mode, int unique)
  1620. {
  1621.     FILE *fout, *din;
  1622.     struct stat st;
  1623.     int (*closefunc) ();
  1624.     char *gunique(char *local);
  1625.     time_t start_time = time(NULL);
  1626.  
  1627.     struct aclmember *entry = NULL;
  1628.  
  1629. #ifndef AMIGA
  1630.     int fdout;
  1631. #endif
  1632.  
  1633. #ifdef OVERWRITE
  1634.     int overwrite = 1;
  1635.  
  1636. #endif /* OVERWRITE */
  1637.  
  1638. #ifdef UPLOAD
  1639.     int open_flags = (O_RDWR | O_CREAT |
  1640.               ((mode && *mode == 'a') ? O_APPEND : O_TRUNC));
  1641.  
  1642.     mode_t oldmask;
  1643.     int f_mode = -1,
  1644.       match_value = -1;
  1645.     uid_t uid;
  1646.     gid_t gid;
  1647.     uid_t oldid;
  1648.     int trunc = O_TRUNC;
  1649.     int valid = 0;
  1650.  
  1651. #endif /* UPLOAD */
  1652.  
  1653. #ifdef AMIGA
  1654.     /* convert unix path (with ".." and ".") to amiga path */
  1655.     UnixToAmiga(name);
  1656.  
  1657.     /* check if user is allowed to access this directory */
  1658.     if (!CheckAccess(name, TRUE))
  1659.     {
  1660.         errno = EACCES;
  1661.         perror_reply(550, name);
  1662.         return;
  1663.     }
  1664. #endif
  1665.  
  1666.     if (unique && stat(name, &st) == 0 &&
  1667.         (name = gunique(name)) == NULL)
  1668.         return;
  1669.  
  1670.     /*
  1671.      * check the filename, is it legal?
  1672.      */
  1673.     if ( (fn_check(name)) <= 0 )
  1674.         return;
  1675.  
  1676. #ifdef OVERWRITE
  1677.     /* if overwrite permission denied and file exists... then deny the user
  1678.      * permission to write the file. */
  1679.     while (getaclentry("overwrite", &entry) && ARG0 && ARG1 != NULL) {
  1680.         if (type_match(ARG1))
  1681.             if (strcmp(ARG0, "yes") != 0) {
  1682.                 overwrite = 0;
  1683.                 open_flags |= O_EXCL;
  1684.             }
  1685.     }
  1686.  
  1687.     if (!overwrite && !stat(name, &st)) {
  1688.         reply(553, "%s: Permission denied. (Overwrite)", name);
  1689.         return;
  1690.     }
  1691. #endif /* OVERWRITE */
  1692.  
  1693. #ifdef UPLOAD
  1694.     if ( (match_value = upl_check(name, &uid, &gid, &f_mode, &valid)) < 0 )
  1695.         return;
  1696.  
  1697.     /* Only truncate on open if the file is not to be appended to. */
  1698.     if (mode[0] == 'a' || (mode[0] == 'r' && mode[0] == '+') || restart_point)
  1699.         trunc = 0;
  1700.  
  1701. #ifndef AMIGA
  1702.     /* if the user has an explicit new file mode, than open the file using
  1703.      * that mode.  We must take care to not let the umask affect the file
  1704.      * mode.
  1705.      * 
  1706.      * else open the file and let the default umask determine the file mode. */
  1707.     if (f_mode >= 0) {
  1708.         oldmask = umask(0000);
  1709.         fdout = open(name, open_flags, f_mode);
  1710.         umask(oldmask);
  1711.     } else
  1712.         fdout = open(name, open_flags, 0666);
  1713.  
  1714.     if (fdout < 0) {
  1715.         perror_reply(553, name);
  1716.         return;
  1717.     }
  1718.     /* if we have a uid and gid, then use them. */
  1719.  
  1720.     if (valid > 0) {
  1721.         oldid = geteuid();
  1722.         (void) seteuid((uid_t) 0);
  1723.         if ((fchown(fdout, uid, gid)) < 0) {
  1724.             (void) seteuid(oldid);
  1725.             perror_reply(550, "fchown");
  1726.             return;
  1727.         }
  1728.         (void) seteuid(oldid);
  1729.     }
  1730. #endif /* AMIGA */
  1731. #endif /* UPLOAD */
  1732.  
  1733.     if (restart_point)
  1734.         mode = "r+w";
  1735.  
  1736. #if defined(UPLOAD) && !defined(AMIGA)
  1737.     fout = fdopen(fdout, mode);
  1738. #else
  1739.     fout = fopen(name, mode);
  1740. #endif /* UPLOAD */
  1741.  
  1742.     closefunc = fclose;
  1743.     if (fout == NULL) {
  1744.         perror_reply(553, name);
  1745.         return;
  1746.     }
  1747.     if (restart_point) {
  1748.         if (type == TYPE_A) {
  1749.             register int i,
  1750.               n,
  1751.               c;
  1752.  
  1753.             n = restart_point;
  1754.             i = 0;
  1755.             while (i++ < n) {
  1756.                 if ((c = getc(fout)) == EOF) {
  1757.                     perror_reply(550, name);
  1758.                     goto done;
  1759.                 }
  1760.                 if (c == '\n')
  1761.                     i++;
  1762.             }
  1763.             /* We must do this seek to "current" position because we are
  1764.              * changing from reading to writing. */
  1765.             if (fseek(fout, 0L, L_INCR) < 0) {
  1766.                 perror_reply(550, name);
  1767.                 goto done;
  1768.             }
  1769.         } else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
  1770.             perror_reply(550, name);
  1771.             goto done;
  1772.         }
  1773.     }
  1774.     din = dataconn(name, (off_t) - 1, "r");
  1775.     if (din == NULL)
  1776.         goto done;
  1777.     if (receive_data(din, fout) == 0) {
  1778.         if (unique)
  1779.             reply(226, "Transfer complete (unique file name:%s).",
  1780.                   name);
  1781.         else
  1782.             reply(226, "Transfer complete.");
  1783.     }
  1784.     (void) fclose(din);
  1785.  
  1786.   dolog:
  1787.     if (log_incoming_xfers && xferlog) {
  1788.         char namebuf[MAXPATHLEN],
  1789.           msg[MAXPATHLEN];
  1790.         int xfertime = time(NULL) - start_time;
  1791.         time_t curtime = time(NULL);
  1792.         int loop;
  1793.  
  1794.         if (!xfertime)
  1795.             xfertime++;
  1796.         realpath(name, namebuf);
  1797.         for (loop = 0; namebuf[loop]; loop++)
  1798.             if (isspace(namebuf[loop]) || iscntrl(namebuf[loop]))
  1799.                 namebuf[loop] = '_';
  1800.         sprintf(msg, "%.24s %d %s %d %s %c %s %c %c %s ftp %d %s\n",
  1801.                 ctime(&curtime),
  1802.                 xfertime,
  1803.                 remotehost,
  1804.                 byte_count,
  1805.                 namebuf,
  1806.                 (type == TYPE_A) ? 'a' : 'b',
  1807.                 opt_string(0),
  1808.                 'i',
  1809.                 anonymous ? 'a' : 'r',
  1810.                 anonymous ? guestpw : pw->pw_name,
  1811.                 authenticated,
  1812.                 authenticated ? authuser : "*"
  1813.             );
  1814.         write(xferlog, msg, strlen(msg));
  1815.     }
  1816.     data = -1;
  1817.     pdata = -1;
  1818.   done:
  1819.     (*closefunc) (fout);
  1820.  
  1821. #if defined(UPLOAD) && defined(AMIGA)
  1822.     /* open() with explicit setting of file mode
  1823.      * does not work on the amiga. We also don't
  1824.      * have fchown(). So we have to set the protection
  1825.      * bits and file owner after the file has been
  1826.      * closed. Let's hope that in the meantime nobody
  1827.      * renames or deletes the file...
  1828.      */
  1829.  
  1830.     if (f_mode >= 0) {
  1831.         oldmask = umask(0000);
  1832.         if ((chmod(name, f_mode)) < 0) {
  1833.           umask(oldmask);
  1834.           perror_reply(550, "chmod");
  1835.           return;
  1836.         }
  1837.         umask(oldmask);
  1838.     }
  1839.  
  1840.     if (valid > 0) {
  1841.         oldid = geteuid();
  1842.         (void) seteuid((uid_t) 0);
  1843.         if ((chown(name, uid, gid)) < 0) {
  1844.             (void) seteuid(oldid);
  1845.             perror_reply(550, "chown");
  1846.             return;
  1847.         }
  1848.         (void) seteuid(oldid);
  1849.     }
  1850. #endif
  1851. }
  1852.  
  1853. FILE *
  1854. getdatasock(char *mode)
  1855. {
  1856.     int s,
  1857.       on = 1,
  1858.       tries;
  1859.  
  1860.     if (data >= 0)
  1861.         return (fdopen(data, mode));
  1862.     (void) seteuid((uid_t) 0);
  1863.     s = socket(AF_INET, SOCK_STREAM, 0);
  1864.     if (s < 0)
  1865.         goto bad;
  1866.     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  1867.                    (char *) &on, sizeof(on)) < 0)
  1868.         goto bad;
  1869.     /* anchor socket to avoid multi-homing problems */
  1870.     data_source.sin_family = AF_INET;
  1871.     data_source.sin_addr = ctrl_addr.sin_addr;
  1872.     for (tries = 1;; tries++) {
  1873.         if (bind(s, (struct sockaddr *) &data_source,
  1874.                  sizeof(data_source)) >= 0)
  1875.             break;
  1876.         if (errno != EADDRINUSE || tries > 10)
  1877.             goto bad;
  1878.         sleep(tries);
  1879.     }
  1880. #if defined(M_UNIX) && !defined(_M_UNIX)  /* bug in old TCP/IP release */
  1881.     {
  1882.         struct linger li;
  1883.         li.l_onoff = 1;
  1884.         li.l_linger = 900;
  1885.         if (setsockopt(s, SOL_SOCKET, SO_LINGER,
  1886.           (char *)&li, sizeof(struct linger)) < 0) {
  1887.             syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
  1888.             goto bad;
  1889.         }
  1890.     }
  1891. #endif
  1892.     (void) seteuid((uid_t) pw->pw_uid);
  1893.  
  1894. #ifdef IPTOS_THROUGHPUT
  1895.     on = IPTOS_THROUGHPUT;
  1896.     if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *) &on, sizeof(int)) < 0)
  1897.           syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  1898. #endif
  1899.  
  1900.     return (fdopen(s, mode));
  1901.   bad:
  1902.     (void) seteuid((uid_t) pw->pw_uid);
  1903.     (void) close(s);
  1904.     return (NULL);
  1905. }
  1906.  
  1907. FILE *
  1908. dataconn(char *name, off_t size, char *mode)
  1909. {
  1910.     char sizebuf[32];
  1911.     FILE *file;
  1912.     int retry = 0;
  1913. #ifdef IPTOS_LOWDELAY
  1914.     int tos;
  1915. #endif
  1916.  
  1917.     file_size = size;
  1918.     byte_count = 0;
  1919.     if (size != (off_t) - 1)
  1920.         (void) sprintf(sizebuf, " (%ld bytes)", size);
  1921.     else
  1922.         (void) strcpy(sizebuf, "");
  1923.     if (pdata >= 0) {
  1924.         struct sockaddr_in from;
  1925.         int s,
  1926.           fromlen = sizeof(from);
  1927.  
  1928.         s = accept(pdata, (struct sockaddr *) &from, &fromlen);
  1929.         if (s < 0) {
  1930.             reply(425, "Can't open data connection.");
  1931.             (void) close(pdata);
  1932.             pdata = -1;
  1933.             return (NULL);
  1934.         }
  1935.         (void) close(pdata);
  1936.         pdata = s;
  1937. #ifdef IPTOS_LOWDELAY
  1938.         tos = IPTOS_LOWDELAY;
  1939.         (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *) &tos,
  1940.                           sizeof(int));
  1941.  
  1942. #endif
  1943.         reply(150, "Opening %s mode data connection for %s%s.",
  1944.               type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  1945.         return (fdopen(pdata, mode));
  1946.     }
  1947.     if (data >= 0) {
  1948.         reply(125, "Using existing data connection for %s%s.",
  1949.               name, sizebuf);
  1950.         usedefault = 1;
  1951.         return (fdopen(data, mode));
  1952.     }
  1953.     if (usedefault)
  1954.         data_dest = his_addr;
  1955.     usedefault = 1;
  1956.     file = getdatasock(mode);
  1957.     if (file == NULL) {
  1958.         reply(425, "Can't create data socket (%s,%d): %s.",
  1959.               inet_ntoa(data_source.sin_addr),
  1960.               ntohs(data_source.sin_port), strerror(errno));
  1961.         return (NULL);
  1962.     }
  1963.     data = fileno(file);
  1964.     while (connect(data, (struct sockaddr *) &data_dest,
  1965.                    sizeof(data_dest)) < 0) {
  1966.         if ((errno == EADDRINUSE || errno == EINTR) && retry < swaitmax) {
  1967.             sleep((unsigned) swaitint);
  1968.             retry += swaitint;
  1969.             continue;
  1970.         }
  1971.         perror_reply(425, "Can't build data connection");
  1972.         (void) fclose(file);
  1973.         data = -1;
  1974.         return (NULL);
  1975.     }
  1976.     reply(150, "Opening %s mode data connection for %s%s.",
  1977.           type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  1978.     return (file);
  1979. }
  1980.  
  1981. /* Tranfer the contents of "instr" to "outstr" peer using the appropriate
  1982.  * encapsulation of the data subject to Mode, Structure, and Type.
  1983.  *
  1984.  * NB: Form isn't handled. */
  1985. send_data(FILE *instr, FILE *outstr, off_t blksize)
  1986. {
  1987.     register int c,
  1988.       cnt;
  1989.     register char *buf;
  1990.     int netfd,
  1991.       filefd;
  1992.  
  1993.     transflag++;
  1994.     if (setjmp(urgcatch)) {
  1995.         transflag = 0;
  1996.         return;
  1997.     }
  1998.     switch (type) {
  1999.  
  2000.     case TYPE_A:
  2001.         while ((c = getc(instr)) != EOF) {
  2002.             byte_count++;
  2003.             if (c == '\n') {
  2004.                 if (ferror(outstr))
  2005.                     goto data_err;
  2006.                 (void) putc('\r', outstr);
  2007.             }
  2008.             (void) putc(c, outstr);
  2009.         }
  2010.         fflush(outstr);
  2011.         transflag = 0;
  2012.         if (ferror(instr))
  2013.             goto file_err;
  2014.         if (ferror(outstr))
  2015.             goto data_err;
  2016.         reply(226, "Transfer complete.");
  2017.         return;
  2018.  
  2019.     case TYPE_I:
  2020.     case TYPE_L:
  2021.         if ((buf = (char *) malloc((u_int) blksize)) == NULL) {
  2022.             transflag = 0;
  2023.             perror_reply(451, "Local resource failure: malloc");
  2024.             return;
  2025.         }
  2026.         netfd = fileno(outstr);
  2027.         filefd = fileno(instr);
  2028.         while ((cnt = read(filefd, buf, (u_int) blksize)) > 0 &&
  2029.                write(netfd, buf, cnt) == cnt)
  2030.             byte_count += cnt;
  2031.         transflag = 0;
  2032.         (void) free(buf);
  2033.         if (cnt != 0) {
  2034.             if (cnt < 0)
  2035.                 goto file_err;
  2036.             goto data_err;
  2037.         }
  2038.         reply(226, "Transfer complete.");
  2039.         return;
  2040.     default:
  2041.         transflag = 0;
  2042.         reply(550, "Unimplemented TYPE %d in send_data", type);
  2043.         return;
  2044.     }
  2045.  
  2046.   data_err:
  2047.     transflag = 0;
  2048.     perror_reply(426, "Data connection");
  2049.     return;
  2050.  
  2051.   file_err:
  2052.     transflag = 0;
  2053.     perror_reply(551, "Error on input file");
  2054. }
  2055.  
  2056. /* Transfer data from peer to "outstr" using the appropriate encapulation of
  2057.  * the data subject to Mode, Structure, and Type.
  2058.  *
  2059.  * N.B.: Form isn't handled. */
  2060. receive_data(FILE *instr, FILE *outstr)
  2061. {
  2062.     register int c;
  2063.     int cnt,
  2064.       bare_lfs = 0;
  2065. #ifndef AMIGA
  2066.     char buf[BUFSIZ];
  2067. #else
  2068.     char *buf;
  2069. #endif
  2070.  
  2071.     transflag++;
  2072.     if (setjmp(urgcatch)) {
  2073.         transflag = 0;
  2074.         return (-1);
  2075.     }
  2076.     switch (type) {
  2077.  
  2078.     case TYPE_I:
  2079.     case TYPE_L:
  2080. #ifdef AMIGA
  2081.     {
  2082.         buf = malloc(amiga_bufsize);
  2083.         if (!buf)
  2084.           goto file_err;
  2085.         while ((cnt = read(fileno(instr), buf, amiga_bufsize)) > 0) {
  2086. #else
  2087.         while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
  2088. #endif
  2089.             if (write(fileno(outstr), buf, cnt) != cnt)
  2090.                 goto file_err;
  2091.             byte_count += cnt;
  2092.         }
  2093.         if (cnt < 0)
  2094. #ifdef AMIGA
  2095.         {
  2096.             free(buf);
  2097.             goto data_err;
  2098.         }
  2099. #else
  2100.             goto data_err;
  2101. #endif
  2102.         transflag = 0;
  2103. #ifdef AMIGA
  2104.         free(buf);
  2105.         return (0);
  2106.     }
  2107. #else
  2108.         return (0);
  2109. #endif
  2110.  
  2111.     case TYPE_E:
  2112.         reply(553, "TYPE E not implemented.");
  2113.         transflag = 0;
  2114.         return (-1);
  2115.  
  2116.     case TYPE_A:
  2117.         while ((c = getc(instr)) != EOF) {
  2118.             byte_count++;
  2119.             if (c == '\n')
  2120.                 bare_lfs++;
  2121.             while (c == '\r') {
  2122.                 if (ferror(outstr))
  2123.                     goto data_err;
  2124.                 if ((c = getc(instr)) != '\n') {
  2125.                     (void) putc('\r', outstr);
  2126.                     if (c == '\0' || c == EOF)
  2127.                         goto contin2;
  2128.                 }
  2129.             }
  2130.             (void) putc(c, outstr);
  2131.           contin2:;
  2132.         }
  2133.         fflush(outstr);
  2134.         if (ferror(instr))
  2135.             goto data_err;
  2136.         if (ferror(outstr))
  2137.             goto file_err;
  2138.         transflag = 0;
  2139.         if (bare_lfs) {
  2140.             lreply(226, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs);
  2141.             printf("   File may not have transferred correctly.\r\n");
  2142.         }
  2143.         return (0);
  2144.     default:
  2145.         reply(550, "Unimplemented TYPE %d in receive_data", type);
  2146.         transflag = 0;
  2147.         return (-1);
  2148.     }
  2149.  
  2150.   data_err:
  2151.     transflag = 0;
  2152.     perror_reply(426, "Data Connection");
  2153.     return (-1);
  2154.  
  2155.   file_err:
  2156.     transflag = 0;
  2157.     perror_reply(452, "Error writing file");
  2158.     return (-1);
  2159. }
  2160.  
  2161. statfilecmd(char *filename)
  2162. {
  2163.     char line[BUFSIZ];
  2164.     FILE *fin;
  2165.     int c;
  2166.  
  2167. #ifdef AMIGA
  2168.     /* convert unix path (with ".." and ".") to amiga path */
  2169.     UnixToAmiga(filename);
  2170.  
  2171.     /* check if user is allowed to access this directory */
  2172.     if (!CheckAccess(filename, FALSE))
  2173.     {
  2174.         errno = EACCES;
  2175.         perror_reply(550, filename);
  2176.         return;
  2177.     }
  2178. #endif
  2179.  
  2180.     if (anonymous && dolreplies)
  2181.         (void) sprintf(line, ls_long, filename);
  2182.     else
  2183.         (void) sprintf(line, ls_short, filename);
  2184.     fin = ftpd_popen(line, "r", 0);
  2185.     lreply(211, "status of %s:", filename);
  2186.     while ((c = getc(fin)) != EOF) {
  2187.         if (c == '\n') {
  2188.             if (ferror(stdout)) {
  2189.                 perror_reply(421, "control connection");
  2190.                 (void) ftpd_pclose(fin);
  2191.                 dologout(1);
  2192.                 /* NOTREACHED */
  2193.             }
  2194.             if (ferror(fin)) {
  2195.                 perror_reply(551, filename);
  2196.                 (void) ftpd_pclose(fin);
  2197.                 return;
  2198.             }
  2199.             (void) putc('\r', stdout);
  2200.         }
  2201.         (void) putc(c, stdout);
  2202.     }
  2203.     (void) ftpd_pclose(fin);
  2204.     reply(211, "End of Status");
  2205. }
  2206.  
  2207. statcmd(void)
  2208. {
  2209.     struct sockaddr_in *sin;
  2210.     u_char *a,
  2211.      *p;
  2212.  
  2213.     lreply(211, "%s FTP server status:", hostname);
  2214.     printf("     %s\r\n", version);
  2215.     printf("     Connected to %s", remotehost);
  2216.     if (!isdigit(remotehost[0]))
  2217.         printf(" (%s)", inet_ntoa(his_addr.sin_addr));
  2218.     printf("\r\n");
  2219.     if (logged_in) {
  2220.         if (anonymous)
  2221.             printf("     Logged in anonymously\r\n");
  2222.         else
  2223.             printf("     Logged in as %s\r\n", pw->pw_name);
  2224.     } else if (askpasswd)
  2225.         printf("     Waiting for password\r\n");
  2226.     else
  2227.         printf("     Waiting for user name\r\n");
  2228.     printf("     TYPE: %s", typenames[type]);
  2229.     if (type == TYPE_A || type == TYPE_E)
  2230.         printf(", FORM: %s", formnames[form]);
  2231.     if (type == TYPE_L)
  2232. #if NBBY == 8
  2233.         printf(" %d", NBBY);
  2234. #else
  2235.         printf(" %d", bytesize);/* need definition! */
  2236. #endif
  2237.     printf("; STRUcture: %s; transfer MODE: %s\r\n",
  2238.            strunames[stru], modenames[mode]);
  2239.     if (data != -1)
  2240.         printf("     Data connection open\r\n");
  2241.     else if (pdata != -1) {
  2242.         printf("     in Passive mode");
  2243.         sin = &pasv_addr;
  2244.         goto printaddr;
  2245.     } else if (usedefault == 0) {
  2246.         printf("     PORT");
  2247.         sin = &data_dest;
  2248.       printaddr:
  2249.         a = (u_char *) & sin->sin_addr;
  2250.         p = (u_char *) & sin->sin_port;
  2251. #define UC(b) (((int) b) & 0xff)
  2252.         printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
  2253.                UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  2254. #undef UC
  2255.     } else
  2256.         printf("     No data connection\r\n");
  2257.     reply(211, "End of status");
  2258. }
  2259.  
  2260. fatal(char *s)
  2261. {
  2262.     reply(451, "Error in server: %s\n", s);
  2263.     reply(221, "Closing connection due to server error.");
  2264.     dologout(0);
  2265.     /* NOTREACHED */
  2266. }
  2267.  
  2268. #if defined (HAVE_VPRINTF)
  2269. /* VARARGS2 */
  2270. reply(va_alist)
  2271.   va_dcl
  2272. {
  2273.     int n;
  2274.     char *fmt;
  2275.     va_list ap;
  2276.     
  2277.     va_start(ap);
  2278.     /* first argument is always the return code */
  2279.     n = va_arg(ap, int);
  2280.     /* second argument is always fmt string     */
  2281.     fmt = va_arg(ap, char *);
  2282.  
  2283.     if (autospout != NULL) {
  2284.         char *ptr = autospout;
  2285.  
  2286.         printf("%d-", n);
  2287.         while (*ptr) {
  2288.             if (*ptr == '\n') {
  2289.                 fputs("\r\n", stdout);
  2290.                 if (*(++ptr))
  2291.                     printf("%03d-", n);
  2292.             } else {
  2293. #ifndef AMIGA
  2294.                 putchar(*ptr++);
  2295. #else
  2296.                 putchar(*ptr);
  2297.                 *ptr++;
  2298. #endif
  2299.             }
  2300.         }
  2301.         if (*(--ptr) != '\n')
  2302.             printf("\r\n");
  2303.         if (autospout_free) {
  2304.             (void) free(autospout);
  2305.             autospout_free = 0;
  2306.         }
  2307.         autospout = 0;
  2308.     }
  2309.     printf("%d ", n);
  2310.     vprintf(fmt, ap);
  2311.     printf("\r\n");
  2312.     (void) fflush(stdout);
  2313.  
  2314.     if (debug) {
  2315.         char buf[BUFSIZ];
  2316.         (void) vsprintf(buf, fmt, ap);
  2317.  
  2318.         syslog(LOG_DEBUG, "<--- %d ", n);
  2319.         syslog(LOG_DEBUG, buf);
  2320.     }
  2321.  
  2322.     va_end(ap);
  2323. }
  2324.  
  2325. /* VARARGS2 */
  2326. lreply(va_alist)
  2327.   va_dcl
  2328. {
  2329.     va_list ap;
  2330.     int n;
  2331.     char *fmt;
  2332.  
  2333.     va_start(ap);
  2334.     /* first argument is always the return code */
  2335.     n = va_arg(ap, int);
  2336.     /* second argument is always fmt string     */
  2337.     fmt = va_arg(ap, char *);
  2338.  
  2339.     if (!dolreplies)
  2340.         return;
  2341.     printf("%d-", n);
  2342.     vprintf(fmt, ap);
  2343.     printf("\r\n");
  2344.     (void) fflush(stdout);
  2345.  
  2346.     if (debug) {
  2347.         char buf[BUFSIZ];
  2348.         (void) vsprintf(buf, fmt, ap);
  2349.  
  2350.         syslog(LOG_DEBUG, "<--- %d- ", n);
  2351.         syslog(LOG_DEBUG, buf);
  2352.     }
  2353.  
  2354.     va_end(ap);
  2355. }
  2356.  
  2357. #else
  2358. /* VARARGS2 */
  2359. reply(int n, char *fmt, int p0, int p1, int p2, int p3, int p4, int p5)
  2360. {
  2361.     if (autospout != NULL) {
  2362.         char *ptr = autospout;
  2363.  
  2364.         printf("%d-", n);
  2365.         while (*ptr) {
  2366.             if (*ptr == '\n') {
  2367.                 printf("\r\n");
  2368.                 if (*(++ptr))
  2369.                     printf("%d-", n);
  2370.             } else {
  2371. #ifndef AMIGA
  2372.                 putchar(*ptr++);
  2373. #else
  2374.                 putchar(*ptr);
  2375.                 *ptr++;
  2376. #endif
  2377.             }
  2378.         }
  2379.         if (*(--ptr) != '\n')
  2380.             printf("\r\n");
  2381.         if (autospout_free) {
  2382.             (void) free(autospout);
  2383.             autospout_free = 0;
  2384.         }
  2385.         autospout = 0;
  2386.     }
  2387.     printf("%d ", n);
  2388.     printf(fmt, p0, p1, p2, p3, p4, p5);
  2389.     printf("\r\n");
  2390.     (void) fflush(stdout);
  2391.     if (debug) {
  2392.         syslog(LOG_DEBUG, "<--- %d ", n);
  2393.         syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
  2394.     }
  2395. }
  2396.  
  2397. /* VARARGS2 */
  2398. lreply(int n, char *fmt, int p0, int p1, int p2, int p3, int p4, int p5)
  2399. {
  2400.     if (!dolreplies)
  2401.         return;
  2402.     printf("%d-", n);
  2403.     printf(fmt, p0, p1, p2, p3, p4, p5);
  2404.     printf("\r\n");
  2405.     (void) fflush(stdout);
  2406.     if (debug) {
  2407.         syslog(LOG_DEBUG, "<--- %d- ", n);
  2408.         syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
  2409.     }
  2410. }
  2411. #endif
  2412.  
  2413. ack(char *s)
  2414. {
  2415.     reply(250, "%s command successful.", s);
  2416. }
  2417.  
  2418. nack(char *s)
  2419. {
  2420.     reply(502, "%s command not implemented.", s);
  2421. }
  2422.  
  2423. /* ARGSUSED */
  2424. yyerror(char *s)
  2425. {
  2426.     char *cp;
  2427.  
  2428.     if ((cp = strchr(cbuf, '\n')) != NULL)
  2429.         *cp = '\0';
  2430.     reply(500, "'%s': command not understood.", cbuf);
  2431. }
  2432.  
  2433. delete(char *name)
  2434. {
  2435.     struct stat st;
  2436.  
  2437. #ifdef AMIGA
  2438.     /* convert unix path (with ".." and ".") to amiga path */
  2439.     UnixToAmiga(name);
  2440.  
  2441.     /* check if user is allowed to access this directory */
  2442.     if (!CheckAccess(name, FALSE))
  2443.     {
  2444.         errno = EACCES;
  2445.         perror_reply(550, name);
  2446.         return;
  2447.     }
  2448. #endif
  2449.  
  2450.     /*
  2451.      * delete permission?
  2452.      */
  2453.  
  2454.     if ( (del_check(name)) == 0 )
  2455.         return;
  2456.  
  2457.     if (lstat(name, &st) < 0) {
  2458.         perror_reply(550, name);
  2459.         return;
  2460.     }
  2461.  
  2462.     if ((st.st_mode & S_IFMT) == S_IFDIR) {
  2463.         if (rmdir(name) < 0) {
  2464.             perror_reply(550, name);
  2465.             return;
  2466.         }
  2467.         goto done;
  2468.     }
  2469.  
  2470.     if (unlink(name) < 0) {
  2471.         perror_reply(550, name);
  2472.         return;
  2473.     }
  2474.  
  2475.   done:
  2476.     {
  2477.         char path[MAXPATHLEN];
  2478.  
  2479.         realpath(name, path);
  2480.  
  2481.         if (anonymous) {
  2482.             syslog(LOG_NOTICE, "%s of %s [%s] deleted %s", guestpw, remotehost,
  2483.                    remoteaddr, path);
  2484.         } else {
  2485.             syslog(LOG_NOTICE, "%s of %s [%s] deleted %s", pw->pw_name,
  2486.                    remotehost, remoteaddr, path);
  2487.         }
  2488.     }
  2489.  
  2490.     ack("DELE");
  2491. }
  2492.  
  2493. cwd(char *path)
  2494. {
  2495.     struct aclmember *entry = NULL;
  2496.     char cdpath[MAXPATHLEN + 1];
  2497.  
  2498. #ifdef AMIGA
  2499.     /* convert unix path (with ".." and ".") to amiga path */
  2500.     UnixToAmiga(path);
  2501.  
  2502.     /* check if user is allowed to access this directory */
  2503.     if (!CheckAccess(path, FALSE))
  2504.     {
  2505.         errno = EACCES;
  2506.         perror_reply(550, path);
  2507.         return;
  2508.     }
  2509. #endif
  2510.       
  2511.     if (chdir(path) < 0) {
  2512.         /* alias checking */
  2513.         while (getaclentry("alias", &entry) && ARG0 && ARG1 != NULL) {
  2514.             if (!strcasecmp(ARG0, path)) {
  2515.                 if (chdir(ARG1) < 0)
  2516.                     perror_reply(550, path);
  2517.                 else {
  2518.                     show_message(250, C_WD);
  2519.                     show_readme(250, C_WD);
  2520.                     ack("CWD");
  2521.                 }
  2522.                 return;
  2523.             }
  2524.         }
  2525.  
  2526.     /* check for "cdpath" directories. */
  2527.     entry = (struct aclmember *) NULL;
  2528.         while (getaclentry("cdpath", &entry) && ARG0 != NULL) {
  2529.         strcpy(cdpath,ARG0);
  2530.         strcat(cdpath,"/");
  2531.         strcat(cdpath,path);
  2532.             if (chdir(cdpath) >= 0) {
  2533.                 show_message(250, C_WD);
  2534.                 show_readme(250, C_WD);
  2535.                 ack("CWD");
  2536.                 return;
  2537.             }
  2538.         }
  2539.         perror_reply(550,path);
  2540.     } else {
  2541.         show_message(250, C_WD);
  2542.         show_readme(250, C_WD);
  2543.         ack("CWD");
  2544.     }
  2545. }
  2546.  
  2547. makedir(char *name)
  2548. {
  2549.     uid_t uid;
  2550.     gid_t gid;
  2551.     int   valid = 0;
  2552.  
  2553. #ifdef AMIGA
  2554.     /* convert unix path (with ".." and ".") to amiga path */
  2555.     UnixToAmiga(name);
  2556.  
  2557.     /* check if user is allowed to access this directory */
  2558.     if (!CheckAccess(name, TRUE))
  2559.     {
  2560.         errno = EACCES;
  2561.         perror_reply(550, name);
  2562.         return;
  2563.     }
  2564. #endif
  2565.  
  2566.     /*
  2567.      * check the directory, can we mkdir here?
  2568.      */
  2569.     if ( (dir_check(name, &uid, &gid, &valid)) <= 0 )
  2570.         return;
  2571.  
  2572.     /*
  2573.      * check the filename, is it legal?
  2574.      */
  2575.     if ( (fn_check(name)) <= 0 )
  2576.         return;
  2577.  
  2578.     if (mkdir(name, 0777) < 0) {
  2579.         perror_reply(550, name);
  2580.     return;
  2581.     }
  2582.  
  2583.     reply(257, "MKD command successful.");
  2584. }
  2585.  
  2586. removedir(char *name)
  2587. {
  2588.     int c, d;  /* dummy variables */
  2589.         int valid = 0;
  2590.  
  2591. #ifdef AMIGA
  2592.     /* convert unix path (with ".." and ".") to amiga path */
  2593.     UnixToAmiga(name);
  2594.  
  2595.     /* check if user is allowed to access this directory */
  2596.     if (!CheckAccess(name, FALSE))
  2597.     {
  2598.         errno = EACCES;
  2599.         perror_reply(550, name);
  2600.         return;
  2601.     }
  2602. #endif
  2603.  
  2604.     /*
  2605.      * check the directory, can we rmdir here?
  2606.      */
  2607.     if ( (dir_check(name, &c, &d, &valid)) <= 0 )
  2608.         return;
  2609.  
  2610.     /*
  2611.      * delete permission?
  2612.      */
  2613.  
  2614.     if ( (del_check(name)) == 0 )
  2615.         return;
  2616.  
  2617.     if (rmdir(name) < 0)
  2618.         perror_reply(550, name);
  2619.     else
  2620.         ack("RMD");
  2621. }
  2622.  
  2623. pwd(void)
  2624. {
  2625.     char path[MAXPATHLEN + 1];
  2626. #ifdef HAVE_GETCWD
  2627.     extern char *getcwd();
  2628. #else
  2629.     extern char *getwd(char *);
  2630. #endif
  2631.  
  2632. #ifdef HAVE_GETCWD
  2633.     if (getcwd(path,MAXPATHLEN) == (char *) NULL)
  2634. #else
  2635.     if (getwd(path) == (char *) NULL)
  2636. #endif
  2637.         reply(550, "%s.", path);
  2638.     else
  2639.         reply(257, "\"%s\" is current directory.", path);
  2640. }
  2641.  
  2642. char *
  2643. renamefrom(char *name)
  2644. {
  2645.     struct stat st;
  2646.  
  2647. #ifdef AMIGA
  2648.     /* convert unix path (with ".." and ".") to amiga path */
  2649.     UnixToAmiga(name);
  2650.  
  2651.     /* check if user is allowed to access this directory */
  2652.     if (!CheckAccess(name, FALSE))
  2653.     {
  2654.         errno = EACCES;
  2655.         perror_reply(550, name);
  2656.         return;
  2657.     }
  2658. #endif /* AMIGA */
  2659.  
  2660.     if (lstat(name, &st) < 0) {
  2661.         perror_reply(550, name);
  2662.         return ((char *) 0);
  2663.     }
  2664.  
  2665.     /* if rename permission denied and file exists... then deny the user
  2666.      * permission to rename the file. 
  2667.      */
  2668.     while (getaclentry("rename", &entry) && ARG0 && ARG1 != NULL) {
  2669.         if (type_match(ARG1))
  2670.             if (strcmp(ARG0, "yes")) {
  2671.                 reply(553, "%s: Permission denied. (rename)", name);
  2672.                 return ((char *) 0);
  2673.             }
  2674.     }
  2675.  
  2676.     reply(350, "File exists, ready for destination name");
  2677.     return (name);
  2678. }
  2679.  
  2680. renamecmd(char *from, char *to)
  2681. {
  2682. #ifdef AMIGA
  2683.     /* convert unix path (with ".." and ".") to amiga path */
  2684.     UnixToAmiga(from);
  2685.     UnixToAmiga(to);
  2686.  
  2687.     /* check if user is allowed to access this directory */
  2688.     if (!CheckAccess(from, FALSE))
  2689.     {
  2690.         errno = EACCES;
  2691.         perror_reply(550, from);
  2692.         return;
  2693.     }
  2694.  
  2695.     if (!CheckAccess(to, TRUE))
  2696.     {
  2697.        errno = EACCES;
  2698.        perror_reply(550, to);
  2699.        return;
  2700.     }
  2701. #endif
  2702.  
  2703.     /*
  2704.      * check the filename, is it legal?
  2705.      */
  2706.     if ( (fn_check(to)) == 0 )
  2707.         return;
  2708.  
  2709.     if (rename(from, to) < 0)
  2710.         perror_reply(550, "rename");
  2711.     else
  2712.         ack("RNTO");
  2713. }
  2714.  
  2715. dolog(struct sockaddr_in *sin)
  2716. {
  2717.     struct hostent *hp;
  2718.     char *blah;
  2719.  
  2720. #ifdef    DNS_TRYAGAIN
  2721.     int num_dns_tries = 0;
  2722.     /*
  2723.      * 27-Apr-93    EHK/BM
  2724.      * far away connections might take some time to get their IP address
  2725.      * resolved. That's why we try again -- maybe our DNS cache has the
  2726.      * PTR-RR now. This code is sloppy. Far better is to check what the
  2727.      * resolver returned so that in case of error, there's no need to
  2728.      * try again.
  2729.      */
  2730. dns_again:
  2731.      hp = gethostbyaddr((char *) &sin->sin_addr,
  2732.                                 sizeof (struct in_addr), AF_INET);
  2733.  
  2734.      if ( !hp && ++num_dns_tries <= 1 ) {
  2735.         sleep(3);
  2736.         goto dns_again;         /* try DNS lookup once more     */
  2737.      }
  2738. #else
  2739.     hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET);
  2740. #endif
  2741.  
  2742.     blah = inet_ntoa(sin->sin_addr);
  2743.  
  2744.     (void) strncpy(remoteaddr, blah, sizeof(remoteaddr));
  2745.  
  2746.     if (!strcmp(remoteaddr, "0.0.0.0")) {
  2747.         nameserved = 1;
  2748.         strncpy(remotehost, "localhost", sizeof(remotehost));
  2749.     } else {
  2750.         if (hp) {
  2751.             nameserved = 1;
  2752.             (void) strncpy(remotehost, hp->h_name, sizeof(remotehost));
  2753.         } else {
  2754.             nameserved = 0;
  2755.             (void) strncpy(remotehost, remoteaddr, sizeof(remotehost));
  2756.         }
  2757.     }
  2758.  
  2759. #ifdef SETPROCTITLE
  2760.     sprintf(proctitle, "%s: connected", remotehost);
  2761.     setproctitle(proctitle);
  2762. #endif /* SETPROCTITLE */
  2763.  
  2764.     if (logging)
  2765.         syslog(LOG_INFO, "connection from %s [%s]", remotehost,
  2766.                remoteaddr);
  2767. }
  2768.  
  2769. /* Record logout in wtmp file and exit with supplied status. */
  2770. dologout(int status)
  2771. {
  2772.     if (logged_in) {
  2773.         (void) seteuid((uid_t) 0);
  2774.         logwtmp(ttyline, "", "");
  2775.     }
  2776.     syslog(LOG_INFO, "FTP session closed");
  2777.     if (xferlog)
  2778.         close(xferlog);
  2779.     acl_remove();
  2780.     /* beware of flushing buffers after a SIGPIPE */
  2781. #ifndef AMIGA
  2782.     _exit(status);
  2783. #else
  2784.     exit(status);
  2785. #endif
  2786. }
  2787.  
  2788. SIGNAL_TYPE
  2789. myoob(int sig)
  2790. {
  2791.     char *cp;
  2792.  
  2793.     /* only process if transfer occurring */
  2794.     if (!transflag)
  2795.         return;
  2796.     cp = tmpline;
  2797.     if (getline(cp, 7, stdin) == NULL) {
  2798.         reply(221, "You could at least say goodbye.");
  2799.         dologout(0);
  2800.     }
  2801.     upper(cp);
  2802.     if (strcmp(cp, "ABOR\r\n") == 0) {
  2803.         tmpline[0] = '\0';
  2804.         reply(426, "Transfer aborted. Data connection closed.");
  2805.         reply(226, "Abort successful");
  2806.         longjmp(urgcatch, 1);
  2807.     }
  2808.     if (strcmp(cp, "STAT\r\n") == 0) {
  2809.         if (file_size != (off_t) - 1)
  2810.             reply(213, "Status: %lu of %lu bytes transferred",
  2811.                   byte_count, file_size);
  2812.         else
  2813.             reply(213, "Status: %lu bytes transferred", byte_count);
  2814.     }
  2815. }
  2816.  
  2817. /* Note: a response of 425 is not mentioned as a possible response to the
  2818.  * PASV command in RFC959. However, it has been blessed as a legitimate
  2819.  * response by Jon Postel in a telephone conversation with Rick Adams on 25
  2820.  * Jan 89. */
  2821. passive(void)
  2822. {
  2823.     int len;
  2824.     register char *p,
  2825.      *a;
  2826.  
  2827.     pdata = socket(AF_INET, SOCK_STREAM, 0);
  2828.     if (pdata < 0) {
  2829.         perror_reply(425, "Can't open passive connection");
  2830.         return;
  2831.     }
  2832.     pasv_addr = ctrl_addr;
  2833.     pasv_addr.sin_port = 0;
  2834.     (void) seteuid((uid_t) 0);
  2835.     if (bind(pdata, (struct sockaddr *) &pasv_addr, sizeof(pasv_addr)) < 0) {
  2836.         (void) seteuid((uid_t) pw->pw_uid);
  2837.         goto pasv_error;
  2838.     }
  2839.     (void) seteuid((uid_t) pw->pw_uid);
  2840.     len = sizeof(pasv_addr);
  2841.     if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
  2842.         goto pasv_error;
  2843.     if (listen(pdata, 1) < 0)
  2844.         goto pasv_error;
  2845.     a = (char *) &pasv_addr.sin_addr;
  2846.     p = (char *) &pasv_addr.sin_port;
  2847.  
  2848. #define UC(b) (((int) b) & 0xff)
  2849.  
  2850.     reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
  2851.           UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  2852.     return;
  2853.  
  2854.   pasv_error:
  2855.     (void) close(pdata);
  2856.     pdata = -1;
  2857.     perror_reply(425, "Can't open passive connection");
  2858.     return;
  2859. }
  2860.  
  2861. /* Generate unique name for file with basename "local". The file named
  2862.  * "local" is already known to exist. Generates failure reply on error. */
  2863. char *
  2864. gunique(char *local)
  2865. {
  2866.     static char new[MAXPATHLEN];
  2867.     struct stat st;
  2868.     char *cp = strrchr(local, '/');
  2869.     int count = 0;
  2870.  
  2871.     if (cp)
  2872.         *cp = '\0';
  2873. #ifndef AMIGA
  2874.     if (stat(cp ? local : ".", &st) < 0) {
  2875.         perror_reply(553, cp ? local : ".");
  2876. #else
  2877.     if (stat(cp ? local : "", &st) < 0) {
  2878.         perror_reply(553, cp ? local : "");
  2879. #endif
  2880.         return ((char *) 0);
  2881.     }
  2882.     if (cp)
  2883.         *cp = '/';
  2884.     (void) strcpy(new, local);
  2885.     cp = new + strlen(new);
  2886.     *cp++ = '.';
  2887.     for (count = 1; count < 100; count++) {
  2888.         (void) sprintf(cp, "%d", count);
  2889.         if (stat(new, &st) < 0)
  2890.             return (new);
  2891.     }
  2892.     reply(452, "Unique file name cannot be created.");
  2893.     return ((char *) 0);
  2894. }
  2895.  
  2896. /* Format and send reply containing system error number. */
  2897. perror_reply(int code, char *string)
  2898. {
  2899.     reply(code, "%s: %s.", string, strerror(errno));
  2900. }
  2901.  
  2902. static char *onefile[] =
  2903. {"", 0};
  2904.  
  2905. send_file_list(char *whichfiles)
  2906. {
  2907.     struct stat st;
  2908.     DIR *dirp = NULL;
  2909.  
  2910. #ifdef HAVE_DIRENT
  2911.     struct dirent *dir;
  2912. #else
  2913.     struct direct *dir;
  2914. #endif
  2915.  
  2916.     FILE *dout = NULL;
  2917.     register char **dirlist,
  2918.      *dirname;
  2919.     int simple = 0;
  2920.     char *strpbrk(const char *, const char *);
  2921.  
  2922. #ifdef AMIGA
  2923.     /* convert unix path (with ".." and ".") to amiga path */
  2924.     UnixToAmiga(whichfiles);
  2925.  
  2926.     /* check if user is allowed to access this directory */
  2927.     if (!CheckAccess(whichfiles, TRUE))
  2928.     {
  2929.         errno = EACCES;
  2930.         perror_reply(550, whichfiles);
  2931.         return;
  2932.     }
  2933. #endif
  2934.  
  2935.     if (strpbrk(whichfiles, "~{[*?") != NULL) {
  2936.         extern char **ftpglob(register char *v),
  2937.          *globerr;
  2938.  
  2939.         globerr = NULL;
  2940.         dirlist = ftpglob(whichfiles);
  2941.         if (globerr != NULL) {
  2942.             reply(550, globerr);
  2943.             return;
  2944.         } else if (dirlist == NULL) {
  2945.             errno = ENOENT;
  2946.             perror_reply(550, whichfiles);
  2947.             return;
  2948.         }
  2949.     } else {
  2950.         onefile[0] = whichfiles;
  2951.         dirlist = onefile;
  2952.         simple = 1;
  2953.     }
  2954.  
  2955.     if (setjmp(urgcatch)) {
  2956.         transflag = 0;
  2957.         return;
  2958.     }
  2959.     while ((dirname = *dirlist++) != NULL) {
  2960.         if (stat(dirname, &st) < 0) {
  2961.             /* If user typed "ls -l", etc, and the client used NLST, do what
  2962.              * the user meant. */
  2963.             if (dirname[0] == '-' && *dirlist == NULL && transflag == 0) {
  2964. #ifdef AMIGA
  2965.                 char *realdirname;
  2966.  
  2967.                 realdirname = strchr(dirname, ' ');
  2968.                 if (realdirname)
  2969.                 {
  2970.                   char *newdirname;
  2971.  
  2972.                   realdirname++;
  2973.                   if (!CheckAccess(realdirname, FALSE))
  2974.                   {
  2975.                     errno = EACCES;
  2976.                     perror_reply(550, realdirname);
  2977.                     return;
  2978.                   }
  2979.                   if (newdirname = malloc(MAXPATHLEN))
  2980.                   {
  2981.                     *(realdirname-1) = '\0';
  2982.                     sprintf(newdirname, "%s \"%s\"", dirname, realdirname);
  2983.                     *(realdirname-1) = ' ';
  2984.                     retrieve("AmiTCP:bin/ls %s", newdirname);
  2985.                     free (newdirname);
  2986.                   }
  2987.                   else
  2988.                     perror_reply(550, "Local resource failure: malloc");
  2989.                 }
  2990.                 else
  2991.                   retrieve("AmiTCP:bin/ls %s", dirname);
  2992. #else
  2993.                 retrieve("/bin/ls %s", dirname);
  2994. #endif
  2995.                 return;
  2996.             }
  2997.             perror_reply(550, whichfiles);
  2998.             if (dout != NULL) {
  2999.                 (void) fclose(dout);
  3000.                 transflag = 0;
  3001.                 data = -1;
  3002.                 pdata = -1;
  3003.             }
  3004.             return;
  3005.         }
  3006.         if ((st.st_mode & S_IFMT) == S_IFREG) {
  3007.             if (dout == NULL) {
  3008.                 dout = dataconn("file list", (off_t) - 1, "w");
  3009.                 if (dout == NULL)
  3010.                     return;
  3011.                 transflag++;
  3012.             }
  3013.             fprintf(dout, "%s%s\n", dirname,
  3014.                     type == TYPE_A ? "\r" : "");
  3015.             byte_count += strlen(dirname) + 1;
  3016.             continue;
  3017.         } else if ((st.st_mode & S_IFMT) != S_IFDIR)
  3018.             continue;
  3019.  
  3020.         if ((dirp = opendir(dirname)) == NULL)
  3021.             continue;
  3022.  
  3023.         while ((dir = readdir(dirp)) != NULL) {
  3024.             char nbuf[MAXPATHLEN];
  3025.  
  3026. #ifndef AMIGA
  3027. #ifndef HAVE_DIRENT    /* does not have d_namlen */
  3028.             if (dir->d_name[0] == '.' && dir->d_namlen == 1)
  3029. #else
  3030.             if (dir->d_name[0] == '.' && (strlen(dir->d_name) == 1))
  3031. #endif
  3032.                 continue;
  3033. #ifndef HAVE_DIRENT    /* does not have d_namlen */
  3034.             if (dir->d_namlen == 2 && dir->d_name[0] == '.' &&
  3035.                 dir->d_name[1] == '.')
  3036. #else
  3037.             if ((strlen(dir->d_name) == 2) && dir->d_name[0] == '.' &&
  3038.                 dir->d_name[1] == '.')
  3039. #endif
  3040.                 continue;
  3041. #endif /* AMIGA */
  3042.  
  3043. #ifdef AMIGA
  3044.             if(strlen(dirname))
  3045.               sprintf(nbuf, "%s/%s", dirname, dir->d_name);
  3046.             else
  3047.               sprintf(nbuf, "%s", dir->d_name);
  3048. #else
  3049.             sprintf(nbuf, "%s/%s", dirname, dir->d_name);
  3050. #endif
  3051.  
  3052.             /* We have to do a stat to insure it's not a directory or special
  3053.              * file. */
  3054.             if (simple || (stat(nbuf, &st) == 0 &&
  3055.                            (st.st_mode & S_IFMT) == S_IFREG)) {
  3056.                 if (dout == NULL) {
  3057.                     dout = dataconn("file list", (off_t) - 1,
  3058.                                     "w");
  3059.                     if (dout == NULL)
  3060.                         return;
  3061.                     transflag++;
  3062.                 }
  3063. #ifndef AMIGA
  3064.                 if (nbuf[0] == '.' && nbuf[1] == '/')
  3065.                     fprintf(dout, "%s%s\n", &nbuf[2],
  3066.                             type == TYPE_A ? "\r" : "");
  3067.                 else
  3068. #endif
  3069.                     fprintf(dout, "%s%s\n", nbuf,
  3070.                             type == TYPE_A ? "\r" : "");
  3071.                 byte_count += strlen(nbuf) + 1;
  3072.             }
  3073.         }
  3074.         (void) closedir(dirp);
  3075.     }
  3076.  
  3077.     if (dout == NULL)
  3078.         reply(550, "No files found.");
  3079.     else if (ferror(dout) != 0)
  3080.         perror_reply(550, "Data connection");
  3081.     else
  3082.         reply(226, "Transfer complete.");
  3083.  
  3084.     transflag = 0;
  3085.     if (dout != NULL)
  3086.         (void) fclose(dout);
  3087.     data = -1;
  3088.     pdata = -1;
  3089. }
  3090.  
  3091. #ifdef SETPROCTITLE
  3092. # ifndef setproctitle /* because of SCO, we use SCOproctitle instead */
  3093. /* clobber argv so ps will show what we're doing. (stolen from sendmail)
  3094.  * warning, since this is usually started from inetd.conf, it often doesn't
  3095.  * have much of an environment or arglist to overwrite. */
  3096.  
  3097. #ifdef HAVE_PSTAT
  3098. #include <sys/pstat.h>
  3099. #endif
  3100.  
  3101. /* VARARGS2 */
  3102. setproctitle(va_alist)
  3103.   va_dcl
  3104. {
  3105.     va_list ap;
  3106.     char *fmt;
  3107.  
  3108.     register char *p,
  3109.      *bp,
  3110.       ch;
  3111.     register int i;
  3112.     char buf[BUFSIZ];
  3113. #ifdef HAVE_PSTAT
  3114.     union pstun un;
  3115. #endif
  3116.  
  3117.     va_start(ap);
  3118.     /* first argument is always the fmt string */
  3119.     fmt = va_arg(ap, char *);
  3120.  
  3121.     (void) vsprintf(buf, fmt, ap);
  3122.     va_end(ap);
  3123.  
  3124.     /* make ps print our process name */
  3125.     p = Argv[0];
  3126.     *p++ = '-';
  3127.  
  3128.     i = strlen(buf);
  3129. #ifdef HAVE_PSTAT
  3130.     un.pst_command = buf;
  3131.     pstat(PSTAT_SETCMD, un, i, 0, 0);
  3132. #else
  3133.     if (i > LastArgv - p - 2) {
  3134.         i = LastArgv - p - 2;
  3135.         buf[i] = '\0';
  3136.     }
  3137.     bp = buf;
  3138.     while ((ch = *bp++) != (char) NULL)
  3139.         if (ch != '\n' && ch != '\r')
  3140.             *p++ = ch;
  3141.     while (p < LastArgv)
  3142.         *p++ = ' ';
  3143. #endif
  3144. }
  3145. #endif /* setproctitle */
  3146. #endif /* SETPROCTITLE */
  3147.  
  3148. #ifdef KERBEROS
  3149. /* thanks to gshapiro@wpi.wpi.edu for the following kerberosities */
  3150.  
  3151. void
  3152. init_krb()
  3153. {
  3154.     char hostname[100];
  3155.  
  3156. #ifdef HAVE_SYSINFO
  3157.     if (sysinfo(SI_HOSTNAME, hostname, sizeof (hostname)) < 0) {
  3158.         perror("sysinfo");
  3159. #else
  3160.     if (gethostname(hostname, sizeof(hostname)) < 0) {
  3161.         perror("gethostname");
  3162. #endif
  3163.         exit(1);
  3164.     }
  3165.     if (strchr(hostname, '.'))
  3166.         *(strchr(hostname, '.')) = 0;
  3167.  
  3168.     sprintf(krb_ticket_name, "/var/dss/kerberos/tkt/tkt.%d", getpid());
  3169.     krb_set_tkt_string(krb_ticket_name);
  3170.  
  3171.     config_auth();
  3172.  
  3173.     if (krb_svc_init("hesiod", hostname, (char *) NULL, 0, (char *) NULL,
  3174.                      (char *) NULL) != KSUCCESS) {
  3175.         fprintf(stderr, "Couldn't initialize Kerberos\n");
  3176.         exit(1);
  3177.     }
  3178. }
  3179.  
  3180. void
  3181. end_krb()
  3182. {
  3183.     unlink(krb_ticket_name);
  3184. }
  3185. #endif /* KERBEROS */
  3186.  
  3187. #ifdef ULTRIX_AUTH
  3188. static int
  3189. ultrix_check_pass(char *passwd, char *xpasswd)
  3190. {
  3191.     struct svcinfo *svp;
  3192.     int auth_status;
  3193.  
  3194.     if ((svp = getsvc()) == (struct svcinfo *) NULL) {
  3195.         syslog(LOG_WARNING, "getsvc() failed in ultrix_check_pass");
  3196.         return -1;
  3197.     }
  3198.     if (pw == (struct passwd *) NULL) {
  3199.         return -1;
  3200.     }
  3201.     if (((svp->svcauth.seclevel == SEC_UPGRADE) &&
  3202.         (!strcmp(pw->pw_passwd, "*")))
  3203.         || (svp->svcauth.seclevel == SEC_ENHANCED)) {
  3204.         if ((auth_status=authenticate_user(pw, passwd, "/dev/ttypXX")) >= 0) {
  3205.             /* Indicate successful validation */
  3206.             return auth_status;
  3207.         }
  3208.         if (auth_status < 0 && errno == EPERM) {
  3209.             /* Log some information about the failed login attempt. */
  3210.             switch(abs(auth_status)) {
  3211.             case A_EBADPASS:
  3212.                 break;
  3213.             case A_ESOFTEXP:
  3214.                 syslog(LOG_NOTICE, "password will expire soon for user %s",
  3215.                     pw->pw_name);
  3216.                 break;
  3217.             case A_EHARDEXP:
  3218.                 syslog(LOG_NOTICE, "password has expired for user %s",
  3219.                     pw->pw_name);
  3220.                 break;
  3221.             case A_ENOLOGIN:
  3222.                 syslog(LOG_NOTICE, "user %s attempted login to disabled acct",
  3223.                     pw->pw_name);
  3224.                 break;
  3225.             }
  3226.         }
  3227.     }
  3228.     else {
  3229.         if ((*pw->pw_passwd != '\0') && (!strcmp(xpasswd, pw->pw_passwd))) {
  3230.             /* passwd in /etc/passwd isn't empty && encrypted passwd matches */
  3231.             return 0;
  3232.         }
  3233.     }
  3234.     return -1;
  3235. }
  3236. #endif /* ULTRIX_AUTH */
  3237.